(root)/
gettext-0.22.4/
gettext-tools/
src/
msgattrib.c
       1  /* Manipulates attributes of messages in translation catalogs.
       2     Copyright (C) 2001-2007, 2009-2010, 2012-2014, 2016, 2018-2023 Free Software Foundation, Inc.
       3     Written by Bruno Haible <haible@clisp.cons.org>, 2001.
       4  
       5     This program is free software: you can redistribute it and/or modify
       6     it under the terms of the GNU General Public License as published by
       7     the Free Software Foundation; either version 3 of the License, or
       8     (at your option) any later version.
       9  
      10     This program is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13     GNU General Public License for more details.
      14  
      15     You should have received a copy of the GNU General Public License
      16     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  
      19  #ifdef HAVE_CONFIG_H
      20  # include "config.h"
      21  #endif
      22  
      23  #include <getopt.h>
      24  #include <limits.h>
      25  #include <stdio.h>
      26  #include <stdlib.h>
      27  #include <locale.h>
      28  
      29  #include <textstyle.h>
      30  
      31  #include "noreturn.h"
      32  #include "closeout.h"
      33  #include "dir-list.h"
      34  #include "error.h"
      35  #include "error-progname.h"
      36  #include "progname.h"
      37  #include "relocatable.h"
      38  #include "basename-lgpl.h"
      39  #include "message.h"
      40  #include "read-catalog.h"
      41  #include "read-po.h"
      42  #include "read-properties.h"
      43  #include "read-stringtable.h"
      44  #include "write-catalog.h"
      45  #include "write-po.h"
      46  #include "write-properties.h"
      47  #include "write-stringtable.h"
      48  #include "propername.h"
      49  #include "xalloc.h"
      50  #include "gettext.h"
      51  
      52  #define _(str) gettext (str)
      53  
      54  
      55  /* Force output of PO file even if empty.  */
      56  static int force_po;
      57  
      58  /* Bit mask of subsets to remove.  */
      59  enum
      60  {
      61    REMOVE_UNTRANSLATED   = 1 << 0,
      62    REMOVE_TRANSLATED     = 1 << 1,
      63    REMOVE_FUZZY          = 1 << 2,
      64    REMOVE_NONFUZZY       = 1 << 3,
      65    REMOVE_OBSOLETE       = 1 << 4,
      66    REMOVE_NONOBSOLETE    = 1 << 5
      67  };
      68  static int to_remove;
      69  
      70  /* Bit mask of actions to perform on all messages.  */
      71  enum
      72  {
      73    SET_FUZZY             = 1 << 0,
      74    RESET_FUZZY           = 1 << 1,
      75    SET_OBSOLETE          = 1 << 2,
      76    RESET_OBSOLETE        = 1 << 3,
      77    REMOVE_PREV           = 1 << 4,
      78    ADD_PREV              = 1 << 5,
      79    REMOVE_TRANSLATION    = 1 << 6
      80  };
      81  static int to_change;
      82  
      83  /* Long options.  */
      84  static const struct option long_options[] =
      85  {
      86    { "add-location", optional_argument, NULL, 'n' },
      87    { "clear-fuzzy", no_argument, NULL, CHAR_MAX + 8 },
      88    { "clear-obsolete", no_argument, NULL, CHAR_MAX + 10 },
      89    { "clear-previous", no_argument, NULL, CHAR_MAX + 18 },
      90    { "empty", no_argument, NULL, CHAR_MAX + 23 },
      91    { "color", optional_argument, NULL, CHAR_MAX + 19 },
      92    { "directory", required_argument, NULL, 'D' },
      93    { "escape", no_argument, NULL, 'E' },
      94    { "force-po", no_argument, &force_po, 1 },
      95    { "fuzzy", no_argument, NULL, CHAR_MAX + 11 },
      96    { "help", no_argument, NULL, 'h' },
      97    { "ignore-file", required_argument, NULL, CHAR_MAX + 15 },
      98    { "indent", no_argument, NULL, 'i' },
      99    { "no-escape", no_argument, NULL, 'e' },
     100    { "no-fuzzy", no_argument, NULL, CHAR_MAX + 3 },
     101    { "no-location", no_argument, NULL, CHAR_MAX + 22 },
     102    { "no-obsolete", no_argument, NULL, CHAR_MAX + 5 },
     103    { "no-wrap", no_argument, NULL, CHAR_MAX + 13 },
     104    { "obsolete", no_argument, NULL, CHAR_MAX + 12 },
     105    { "only-file", required_argument, NULL, CHAR_MAX + 14 },
     106    { "only-fuzzy", no_argument, NULL, CHAR_MAX + 4 },
     107    { "only-obsolete", no_argument, NULL, CHAR_MAX + 6 },
     108    { "output-file", required_argument, NULL, 'o' },
     109    { "previous", no_argument, NULL, CHAR_MAX + 21 },
     110    { "properties-input", no_argument, NULL, 'P' },
     111    { "properties-output", no_argument, NULL, 'p' },
     112    { "set-fuzzy", no_argument, NULL, CHAR_MAX + 7 },
     113    { "set-obsolete", no_argument, NULL, CHAR_MAX + 9 },
     114    { "sort-by-file", no_argument, NULL, 'F' },
     115    { "sort-output", no_argument, NULL, 's' },
     116    { "stringtable-input", no_argument, NULL, CHAR_MAX + 16 },
     117    { "stringtable-output", no_argument, NULL, CHAR_MAX + 17 },
     118    { "strict", no_argument, NULL, 'S' },
     119    { "style", required_argument, NULL, CHAR_MAX + 20 },
     120    { "translated", no_argument, NULL, CHAR_MAX + 1 },
     121    { "untranslated", no_argument, NULL, CHAR_MAX + 2 },
     122    { "version", no_argument, NULL, 'V' },
     123    { "width", required_argument, NULL, 'w' },
     124    { NULL, 0, NULL, 0 }
     125  };
     126  
     127  
     128  /* Forward declaration of local functions.  */
     129  _GL_NORETURN_FUNC static void usage (int status);
     130  static msgdomain_list_ty *process_msgdomain_list (msgdomain_list_ty *mdlp,
     131                                                    msgdomain_list_ty *only_mdlp,
     132                                                  msgdomain_list_ty *ignore_mdlp);
     133  
     134  
     135  int
     136  main (int argc, char **argv)
     137  {
     138    int optchar;
     139    bool do_help;
     140    bool do_version;
     141    char *output_file;
     142    const char *input_file;
     143    const char *only_file;
     144    const char *ignore_file;
     145    msgdomain_list_ty *only_mdlp;
     146    msgdomain_list_ty *ignore_mdlp;
     147    msgdomain_list_ty *result;
     148    catalog_input_format_ty input_syntax = &input_format_po;
     149    catalog_output_format_ty output_syntax = &output_format_po;
     150    bool sort_by_msgid = false;
     151    bool sort_by_filepos = false;
     152  
     153    /* Set program name for messages.  */
     154    set_program_name (argv[0]);
     155    error_print_progname = maybe_print_progname;
     156  
     157    /* Set locale via LC_ALL.  */
     158    setlocale (LC_ALL, "");
     159  
     160    /* Set the text message domain.  */
     161    bindtextdomain (PACKAGE, relocate (LOCALEDIR));
     162    bindtextdomain ("bison-runtime", relocate (BISON_LOCALEDIR));
     163    textdomain (PACKAGE);
     164  
     165    /* Ensure that write errors on stdout are detected.  */
     166    atexit (close_stdout);
     167  
     168    /* Set default values for variables.  */
     169    do_help = false;
     170    do_version = false;
     171    output_file = NULL;
     172    input_file = NULL;
     173    only_file = NULL;
     174    ignore_file = NULL;
     175  
     176    while ((optchar = getopt_long (argc, argv, "D:eEFhino:pPsVw:", long_options,
     177                                   NULL)) != EOF)
     178      switch (optchar)
     179        {
     180        case '\0':                /* Long option.  */
     181          break;
     182  
     183        case 'D':
     184          dir_list_append (optarg);
     185          break;
     186  
     187        case 'e':
     188          message_print_style_escape (false);
     189          break;
     190  
     191        case 'E':
     192          message_print_style_escape (true);
     193          break;
     194  
     195        case 'F':
     196          sort_by_filepos = true;
     197          break;
     198  
     199        case 'h':
     200          do_help = true;
     201          break;
     202  
     203        case 'i':
     204          message_print_style_indent ();
     205          break;
     206  
     207        case 'n':
     208          if (handle_filepos_comment_option (optarg))
     209            usage (EXIT_FAILURE);
     210          break;
     211  
     212        case 'o':
     213          output_file = optarg;
     214          break;
     215  
     216        case 'p':
     217          output_syntax = &output_format_properties;
     218          break;
     219  
     220        case 'P':
     221          input_syntax = &input_format_properties;
     222          break;
     223  
     224        case 's':
     225          sort_by_msgid = true;
     226          break;
     227  
     228        case 'S':
     229          message_print_style_uniforum ();
     230          break;
     231  
     232        case 'V':
     233          do_version = true;
     234          break;
     235  
     236        case 'w':
     237          {
     238            int value;
     239            char *endp;
     240            value = strtol (optarg, &endp, 10);
     241            if (endp != optarg)
     242              message_page_width_set (value);
     243          }
     244          break;
     245  
     246        case CHAR_MAX + 1: /* --translated */
     247          to_remove |= REMOVE_UNTRANSLATED;
     248          break;
     249  
     250        case CHAR_MAX + 2: /* --untranslated */
     251          to_remove |= REMOVE_TRANSLATED;
     252          break;
     253  
     254        case CHAR_MAX + 3: /* --no-fuzzy */
     255          to_remove |= REMOVE_FUZZY;
     256          break;
     257  
     258        case CHAR_MAX + 4: /* --only-fuzzy */
     259          to_remove |= REMOVE_NONFUZZY;
     260          break;
     261  
     262        case CHAR_MAX + 5: /* --no-obsolete */
     263          to_remove |= REMOVE_OBSOLETE;
     264          break;
     265  
     266        case CHAR_MAX + 6: /* --only-obsolete */
     267          to_remove |= REMOVE_NONOBSOLETE;
     268          break;
     269  
     270        case CHAR_MAX + 7: /* --set-fuzzy */
     271          to_change |= SET_FUZZY;
     272          break;
     273  
     274        case CHAR_MAX + 8: /* --clear-fuzzy */
     275          to_change |= RESET_FUZZY;
     276          break;
     277  
     278        case CHAR_MAX + 9: /* --set-obsolete */
     279          to_change |= SET_OBSOLETE;
     280          break;
     281  
     282        case CHAR_MAX + 10: /* --clear-obsolete */
     283          to_change |= RESET_OBSOLETE;
     284          break;
     285  
     286        case CHAR_MAX + 11: /* --fuzzy */
     287          to_remove |= REMOVE_NONFUZZY;
     288          to_change |= RESET_FUZZY;
     289          break;
     290  
     291        case CHAR_MAX + 12: /* --obsolete */
     292          to_remove |= REMOVE_NONOBSOLETE;
     293          to_change |= RESET_OBSOLETE;
     294          break;
     295  
     296        case CHAR_MAX + 13: /* --no-wrap */
     297          message_page_width_ignore ();
     298          break;
     299  
     300        case CHAR_MAX + 14: /* --only-file */
     301          only_file = optarg;
     302          break;
     303  
     304        case CHAR_MAX + 15: /* --ignore-file */
     305          ignore_file = optarg;
     306          break;
     307  
     308        case CHAR_MAX + 16: /* --stringtable-input */
     309          input_syntax = &input_format_stringtable;
     310          break;
     311  
     312        case CHAR_MAX + 17: /* --stringtable-output */
     313          output_syntax = &output_format_stringtable;
     314          break;
     315  
     316        case CHAR_MAX + 18: /* --clear-previous */
     317          to_change |= REMOVE_PREV;
     318          break;
     319  
     320        case CHAR_MAX + 19: /* --color */
     321          if (handle_color_option (optarg) || color_test_mode)
     322            usage (EXIT_FAILURE);
     323          break;
     324  
     325        case CHAR_MAX + 20: /* --style */
     326          handle_style_option (optarg);
     327          break;
     328  
     329        case CHAR_MAX + 21: /* --previous */
     330          to_change |= ADD_PREV;
     331          break;
     332  
     333        case CHAR_MAX + 22: /* --no-location */
     334          message_print_style_filepos (filepos_comment_none);
     335          break;
     336  
     337        case CHAR_MAX + 23: /* --empty */
     338          to_change |= REMOVE_TRANSLATION;
     339          break;
     340  
     341        default:
     342          usage (EXIT_FAILURE);
     343          /* NOTREACHED */
     344        }
     345  
     346    /* Version information requested.  */
     347    if (do_version)
     348      {
     349        printf ("%s (GNU %s) %s\n", last_component (program_name),
     350                PACKAGE, VERSION);
     351        /* xgettext: no-wrap */
     352        printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
     353  License GPLv3+: GNU GPL version 3 or later <%s>\n\
     354  This is free software: you are free to change and redistribute it.\n\
     355  There is NO WARRANTY, to the extent permitted by law.\n\
     356  "),
     357                "2001-2023", "https://gnu.org/licenses/gpl.html");
     358        printf (_("Written by %s.\n"), proper_name ("Bruno Haible"));
     359        exit (EXIT_SUCCESS);
     360      }
     361  
     362    /* Help is requested.  */
     363    if (do_help)
     364      usage (EXIT_SUCCESS);
     365  
     366    /* Test whether we have an .po file name as argument.  */
     367    if (optind == argc)
     368      input_file = "-";
     369    else if (optind + 1 == argc)
     370      input_file = argv[optind];
     371    else
     372      {
     373        error (EXIT_SUCCESS, 0, _("at most one input file allowed"));
     374        usage (EXIT_FAILURE);
     375      }
     376  
     377    /* Verify selected options.  */
     378    if (sort_by_msgid && sort_by_filepos)
     379      error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
     380             "--sort-output", "--sort-by-file");
     381  
     382    /* Read input file.  */
     383    result = read_catalog_file (input_file, input_syntax);
     384  
     385    /* Read optional files that limit the extent of the attribute changes.  */
     386    only_mdlp = (only_file != NULL
     387                 ? read_catalog_file (only_file, input_syntax)
     388                 : NULL);
     389    ignore_mdlp = (ignore_file != NULL
     390                   ? read_catalog_file (ignore_file, input_syntax)
     391                   : NULL);
     392  
     393    /* Filter the messages and manipulate the attributes.  */
     394    result = process_msgdomain_list (result, only_mdlp, ignore_mdlp);
     395  
     396    /* Sorting the list of messages.  */
     397    if (sort_by_filepos)
     398      msgdomain_list_sort_by_filepos (result);
     399    else if (sort_by_msgid)
     400      msgdomain_list_sort_by_msgid (result);
     401  
     402    /* Write the PO file.  */
     403    msgdomain_list_print (result, output_file, output_syntax, force_po, false);
     404  
     405    exit (EXIT_SUCCESS);
     406  }
     407  
     408  
     409  /* Display usage information and exit.  */
     410  static void
     411  usage (int status)
     412  {
     413    if (status != EXIT_SUCCESS)
     414      fprintf (stderr, _("Try '%s --help' for more information.\n"),
     415               program_name);
     416    else
     417      {
     418        printf (_("\
     419  Usage: %s [OPTION] [INPUTFILE]\n\
     420  "), program_name);
     421        printf ("\n");
     422        /* xgettext: no-wrap */
     423        printf (_("\
     424  Filters the messages of a translation catalog according to their attributes,\n\
     425  and manipulates the attributes.\n"));
     426        printf ("\n");
     427        printf (_("\
     428  Mandatory arguments to long options are mandatory for short options too.\n"));
     429        printf ("\n");
     430        printf (_("\
     431  Input file location:\n"));
     432        printf (_("\
     433    INPUTFILE                   input PO file\n"));
     434        printf (_("\
     435    -D, --directory=DIRECTORY   add DIRECTORY to list for input files search\n"));
     436        printf (_("\
     437  If no input file is given or if it is -, standard input is read.\n"));
     438        printf ("\n");
     439        printf (_("\
     440  Output file location:\n"));
     441        printf (_("\
     442    -o, --output-file=FILE      write output to specified file\n"));
     443        printf (_("\
     444  The results are written to standard output if no output file is specified\n\
     445  or if it is -.\n"));
     446        printf ("\n");
     447        printf (_("\
     448  Message selection:\n"));
     449        printf (_("\
     450        --translated            keep translated, remove untranslated messages\n"));
     451        printf (_("\
     452        --untranslated          keep untranslated, remove translated messages\n"));
     453        printf (_("\
     454        --no-fuzzy              remove 'fuzzy' marked messages\n"));
     455        printf (_("\
     456        --only-fuzzy            keep 'fuzzy' marked messages\n"));
     457        printf (_("\
     458        --no-obsolete           remove obsolete #~ messages\n"));
     459        printf (_("\
     460        --only-obsolete         keep obsolete #~ messages\n"));
     461        printf ("\n");
     462        printf (_("\
     463  Attribute manipulation:\n"));
     464        printf (_("\
     465        --set-fuzzy             set all messages 'fuzzy'\n"));
     466        printf (_("\
     467        --clear-fuzzy           set all messages non-'fuzzy'\n"));
     468        printf (_("\
     469        --set-obsolete          set all messages obsolete\n"));
     470        printf (_("\
     471        --clear-obsolete        set all messages non-obsolete\n"));
     472        printf (_("\
     473        --previous              when setting 'fuzzy', keep previous msgids\n\
     474                                of translated messages.\n"));
     475        printf (_("\
     476        --clear-previous        remove the \"previous msgid\" from all messages\n"));
     477        printf (_("\
     478        --empty                 when removing 'fuzzy', also set msgstr empty\n"));
     479        printf (_("\
     480        --only-file=FILE.po     manipulate only entries listed in FILE.po\n"));
     481        printf (_("\
     482        --ignore-file=FILE.po   manipulate only entries not listed in FILE.po\n"));
     483        printf (_("\
     484        --fuzzy                 synonym for --only-fuzzy --clear-fuzzy\n"));
     485        printf (_("\
     486        --obsolete              synonym for --only-obsolete --clear-obsolete\n"));
     487        printf ("\n");
     488        printf (_("\
     489  Input file syntax:\n"));
     490        printf (_("\
     491    -P, --properties-input      input file is in Java .properties syntax\n"));
     492        printf (_("\
     493        --stringtable-input     input file is in NeXTstep/GNUstep .strings syntax\n"));
     494        printf ("\n");
     495        printf (_("\
     496  Output details:\n"));
     497        printf (_("\
     498        --color                 use colors and other text attributes always\n\
     499        --color=WHEN            use colors and other text attributes if WHEN.\n\
     500                                WHEN may be 'always', 'never', 'auto', or 'html'.\n"));
     501        printf (_("\
     502        --style=STYLEFILE       specify CSS style rule file for --color\n"));
     503        printf (_("\
     504    -e, --no-escape             do not use C escapes in output (default)\n"));
     505        printf (_("\
     506    -E, --escape                use C escapes in output, no extended chars\n"));
     507        printf (_("\
     508        --force-po              write PO file even if empty\n"));
     509        printf (_("\
     510    -i, --indent                write the .po file using indented style\n"));
     511        printf (_("\
     512        --no-location           do not write '#: filename:line' lines\n"));
     513        printf (_("\
     514    -n, --add-location          generate '#: filename:line' lines (default)\n"));
     515        printf (_("\
     516        --strict                write out strict Uniforum conforming .po file\n"));
     517        printf (_("\
     518    -p, --properties-output     write out a Java .properties file\n"));
     519        printf (_("\
     520        --stringtable-output    write out a NeXTstep/GNUstep .strings file\n"));
     521        printf (_("\
     522    -w, --width=NUMBER          set output page width\n"));
     523        printf (_("\
     524        --no-wrap               do not break long message lines, longer than\n\
     525                                the output page width, into several lines\n"));
     526        printf (_("\
     527    -s, --sort-output           generate sorted output\n"));
     528        printf (_("\
     529    -F, --sort-by-file          sort output by file location\n"));
     530        printf ("\n");
     531        printf (_("\
     532  Informative output:\n"));
     533        printf (_("\
     534    -h, --help                  display this help and exit\n"));
     535        printf (_("\
     536    -V, --version               output version information and exit\n"));
     537        printf ("\n");
     538        /* TRANSLATORS: The first placeholder is the web address of the Savannah
     539           project of this package.  The second placeholder is the bug-reporting
     540           email address for this package.  Please add _another line_ saying
     541           "Report translation bugs to <...>\n" with the address for translation
     542           bugs (typically your translation team's web or email address).  */
     543        printf(_("\
     544  Report bugs in the bug tracker at <%s>\n\
     545  or by email to <%s>.\n"),
     546               "https://savannah.gnu.org/projects/gettext",
     547               "bug-gettext@gnu.org");
     548      }
     549  
     550    exit (status);
     551  }
     552  
     553  
     554  /* Return true if a message should be kept.  */
     555  static bool
     556  is_message_selected (const message_ty *mp)
     557  {
     558    /* Always keep the header entry.  */
     559    if (is_header (mp))
     560      return true;
     561  
     562    if ((to_remove & (REMOVE_UNTRANSLATED | REMOVE_TRANSLATED))
     563        && (mp->msgstr[0] == '\0'
     564            ? to_remove & REMOVE_UNTRANSLATED
     565            : to_remove & REMOVE_TRANSLATED))
     566      return false;
     567  
     568    if ((to_remove & (REMOVE_FUZZY | REMOVE_NONFUZZY))
     569        && (mp->is_fuzzy
     570            ? to_remove & REMOVE_FUZZY
     571            : to_remove & REMOVE_NONFUZZY))
     572      return false;
     573  
     574    if ((to_remove & (REMOVE_OBSOLETE | REMOVE_NONOBSOLETE))
     575        && (mp->obsolete
     576            ? to_remove & REMOVE_OBSOLETE
     577            : to_remove & REMOVE_NONOBSOLETE))
     578      return false;
     579  
     580    return true;
     581  }
     582  
     583  
     584  static void
     585  process_message_list (message_list_ty *mlp,
     586                        message_list_ty *only_mlp, message_list_ty *ignore_mlp)
     587  {
     588    /* Keep only the selected messages.  */
     589    message_list_remove_if_not (mlp, is_message_selected);
     590  
     591    /* Change the attributes.  */
     592    if (to_change)
     593      {
     594        size_t j;
     595  
     596        for (j = 0; j < mlp->nitems; j++)
     597          {
     598            message_ty *mp = mlp->item[j];
     599  
     600            /* Attribute changes only affect messages listed in --only-file
     601               and not listed in --ignore-file.  */
     602            if ((only_mlp
     603                 ? message_list_search (only_mlp, mp->msgctxt, mp->msgid) != NULL
     604                 : true)
     605                && (ignore_mlp
     606                    ? message_list_search (ignore_mlp, mp->msgctxt, mp->msgid) == NULL
     607                    : true))
     608              {
     609                if (to_change & SET_FUZZY)
     610                  {
     611                    if ((to_change & ADD_PREV) && !is_header (mp)
     612                        && !mp->is_fuzzy && mp->msgstr[0] != '\0')
     613                      {
     614                        mp->prev_msgctxt =
     615                          (mp->msgctxt != NULL ? xstrdup (mp->msgctxt) : NULL);
     616                        mp->prev_msgid =
     617                          (mp->msgid != NULL ? xstrdup (mp->msgid) : NULL);
     618                        mp->prev_msgid_plural =
     619                          (mp->msgid_plural != NULL
     620                           ? xstrdup (mp->msgid_plural)
     621                           : NULL);
     622                      }
     623                    mp->is_fuzzy = true;
     624                  }
     625  
     626                if (to_change & RESET_FUZZY)
     627                  {
     628                    if ((to_change & REMOVE_TRANSLATION)
     629                        && mp->is_fuzzy && !mp->obsolete)
     630                      {
     631                        unsigned long int nplurals = 0;
     632                        char *msgstr;
     633                        size_t pos;
     634  
     635                        for (pos = 0; pos < mp->msgstr_len; ++pos)
     636                          if (!mp->msgstr[pos])
     637                            ++nplurals;
     638                        free ((char *) mp->msgstr);
     639                        msgstr = XNMALLOC (nplurals, char);
     640                        memset (msgstr, '\0', nplurals);
     641                        mp->msgstr = msgstr;
     642                        mp->msgstr_len = nplurals;
     643                      }
     644                    mp->is_fuzzy = false;
     645                  }
     646                /* Always keep the header entry non-obsolete.  */
     647                if ((to_change & SET_OBSOLETE) && !is_header (mp))
     648                  mp->obsolete = true;
     649                if (to_change & RESET_OBSOLETE)
     650                  mp->obsolete = false;
     651                if (to_change & REMOVE_PREV)
     652                  {
     653                    mp->prev_msgctxt = NULL;
     654                    mp->prev_msgid = NULL;
     655                    mp->prev_msgid_plural = NULL;
     656                  }
     657              }
     658          }
     659      }
     660  }
     661  
     662  
     663  static msgdomain_list_ty *
     664  process_msgdomain_list (msgdomain_list_ty *mdlp,
     665                          msgdomain_list_ty *only_mdlp,
     666                          msgdomain_list_ty *ignore_mdlp)
     667  {
     668    size_t k;
     669  
     670    for (k = 0; k < mdlp->nitems; k++)
     671      process_message_list (mdlp->item[k]->messages,
     672                            only_mdlp
     673                            ? msgdomain_list_sublist (only_mdlp,
     674                                                      mdlp->item[k]->domain,
     675                                                      true)
     676                            : NULL,
     677                            ignore_mdlp
     678                            ? msgdomain_list_sublist (ignore_mdlp,
     679                                                      mdlp->item[k]->domain,
     680                                                      false)
     681                            : NULL);
     682  
     683    return mdlp;
     684  }