(root)/
gettext-0.22.4/
gettext-tools/
src/
msgl-equal.c
       1  /* Message list test for equality.
       2     Copyright (C) 2001-2002, 2005-2006, 2008 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  /* Specification.  */
      24  #include "msgl-equal.h"
      25  
      26  #include <stddef.h>
      27  #include <string.h>
      28  
      29  
      30  static inline bool
      31  msgstr_equal (const char *msgstr1, size_t msgstr1_len,
      32                const char *msgstr2, size_t msgstr2_len)
      33  {
      34    return (msgstr1_len == msgstr2_len
      35            && memcmp (msgstr1, msgstr2, msgstr1_len) == 0);
      36  }
      37  
      38  static bool
      39  msgstr_equal_ignoring_potcdate (const char *msgstr1, size_t msgstr1_len,
      40                                  const char *msgstr2, size_t msgstr2_len)
      41  {
      42    const char *msgstr1_end = msgstr1 + msgstr1_len;
      43    const char *msgstr2_end = msgstr2 + msgstr2_len;
      44    const char *ptr1;
      45    const char *ptr2;
      46    const char *const field = "POT-Creation-Date:";
      47    const ptrdiff_t fieldlen = sizeof ("POT-Creation-Date:") - 1;
      48  
      49    /* Search for the occurrence of field in msgstr1.  */
      50    for (ptr1 = msgstr1;;)
      51      {
      52        if (msgstr1_end - ptr1 < fieldlen)
      53          {
      54            ptr1 = NULL;
      55            break;
      56          }
      57        if (memcmp (ptr1, field, fieldlen) == 0)
      58          break;
      59        ptr1 = (const char *) memchr (ptr1, '\n', msgstr1_end - ptr1);
      60        if (ptr1 == NULL)
      61          break;
      62        ptr1++;
      63      }
      64  
      65    /* Search for the occurrence of field in msgstr2.  */
      66    for (ptr2 = msgstr2;;)
      67      {
      68        if (msgstr2_end - ptr2 < fieldlen)
      69          {
      70            ptr2 = NULL;
      71            break;
      72          }
      73        if (memcmp (ptr2, field, fieldlen) == 0)
      74          break;
      75        ptr2 = (const char *) memchr (ptr2, '\n', msgstr2_end - ptr2);
      76        if (ptr2 == NULL)
      77          break;
      78        ptr2++;
      79      }
      80  
      81    if (ptr1 == NULL)
      82      {
      83        if (ptr2 == NULL)
      84          return msgstr_equal (msgstr1, msgstr1_len, msgstr2, msgstr2_len);
      85      }
      86    else
      87      {
      88        if (ptr2 != NULL)
      89          {
      90            /* Compare, ignoring the lines starting at ptr1 and ptr2.  */
      91            if (msgstr_equal (msgstr1, ptr1 - msgstr1, msgstr2, ptr2 - msgstr2))
      92              {
      93                ptr1 = (const char *) memchr (ptr1, '\n', msgstr1_end - ptr1);
      94                if (ptr1 == NULL)
      95                  ptr1 = msgstr1_end;
      96  
      97                ptr2 = (const char *) memchr (ptr2, '\n', msgstr2_end - ptr2);
      98                if (ptr2 == NULL)
      99                  ptr2 = msgstr2_end;
     100  
     101                return msgstr_equal (ptr1, msgstr1_end - ptr1,
     102                                     ptr2, msgstr2_end - ptr2);
     103              }
     104          }
     105      }
     106    return false;
     107  }
     108  
     109  static inline bool
     110  pos_equal (const lex_pos_ty *pos1, const lex_pos_ty *pos2)
     111  {
     112    return ((pos1->file_name == pos2->file_name
     113             || strcmp (pos1->file_name, pos2->file_name) == 0)
     114            && pos1->line_number == pos2->line_number);
     115  }
     116  
     117  bool
     118  string_list_equal (const string_list_ty *slp1, const string_list_ty *slp2)
     119  {
     120    size_t i, i1, i2;
     121  
     122    i1 = (slp1 != NULL ? slp1->nitems : 0);
     123    i2 = (slp2 != NULL ? slp2->nitems : 0);
     124    if (i1 != i2)
     125      return false;
     126    for (i = 0; i < i1; i++)
     127      if (strcmp (slp1->item[i], slp2->item[i]) != 0)
     128        return false;
     129    return true;
     130  }
     131  
     132  bool
     133  message_equal (const message_ty *mp1, const message_ty *mp2,
     134                 bool ignore_potcdate)
     135  {
     136    size_t i, i1, i2;
     137  
     138    if (!(mp1->msgctxt != NULL
     139          ? mp2->msgctxt != NULL && strcmp (mp1->msgctxt, mp2->msgctxt) == 0
     140          : mp2->msgctxt == NULL))
     141      return false;
     142  
     143    if (strcmp (mp1->msgid, mp2->msgid) != 0)
     144      return false;
     145  
     146    if (!(mp1->msgid_plural != NULL
     147          ? mp2->msgid_plural != NULL
     148            && strcmp (mp1->msgid_plural, mp2->msgid_plural) == 0
     149          : mp2->msgid_plural == NULL))
     150      return false;
     151  
     152    if (is_header (mp1) && ignore_potcdate
     153        ? !msgstr_equal_ignoring_potcdate (mp1->msgstr, mp1->msgstr_len,
     154                                           mp2->msgstr, mp2->msgstr_len)
     155        : !msgstr_equal (mp1->msgstr, mp1->msgstr_len,
     156                         mp2->msgstr, mp2->msgstr_len))
     157      return false;
     158  
     159    if (!pos_equal (&mp1->pos, &mp2->pos))
     160      return false;
     161  
     162    if (!string_list_equal (mp1->comment, mp2->comment))
     163      return false;
     164  
     165    if (!string_list_equal (mp1->comment_dot, mp2->comment_dot))
     166      return false;
     167  
     168    i1 = mp1->filepos_count;
     169    i2 = mp2->filepos_count;
     170    if (i1 != i2)
     171      return false;
     172    for (i = 0; i < i1; i++)
     173      if (!pos_equal (&mp1->filepos[i], &mp2->filepos[i]))
     174        return false;
     175  
     176    if (mp1->is_fuzzy != mp2->is_fuzzy)
     177      return false;
     178  
     179    for (i = 0; i < NFORMATS; i++)
     180      if (mp1->is_format[i] != mp2->is_format[i])
     181        return false;
     182  
     183    if (!(mp1->range.min == mp2->range.min && mp1->range.max == mp2->range.max))
     184      return false;
     185  
     186    if (!(mp1->prev_msgctxt != NULL
     187          ? mp2->prev_msgctxt != NULL
     188            && strcmp (mp1->prev_msgctxt, mp2->prev_msgctxt) == 0
     189          : mp2->prev_msgctxt == NULL))
     190      return false;
     191  
     192    if (!(mp1->prev_msgid != NULL
     193          ? mp2->prev_msgid != NULL
     194            && strcmp (mp1->prev_msgid, mp2->prev_msgid) == 0
     195          : mp2->prev_msgid == NULL))
     196      return false;
     197  
     198    if (!(mp1->prev_msgid_plural != NULL
     199          ? mp2->prev_msgid_plural != NULL
     200            && strcmp (mp1->prev_msgid_plural, mp2->prev_msgid_plural) == 0
     201          : mp2->prev_msgid_plural == NULL))
     202      return false;
     203  
     204    if (mp1->obsolete != mp2->obsolete)
     205      return false;
     206  
     207    return true;
     208  }
     209  
     210  bool
     211  message_list_equal (const message_list_ty *mlp1, const message_list_ty *mlp2,
     212                      bool ignore_potcdate)
     213  {
     214    size_t i, i1, i2;
     215  
     216    i1 = mlp1->nitems;
     217    i2 = mlp2->nitems;
     218    if (i1 != i2)
     219      return false;
     220    for (i = 0; i < i1; i++)
     221      if (!message_equal (mlp1->item[i], mlp2->item[i], ignore_potcdate))
     222        return false;
     223    return true;
     224  }
     225  
     226  static inline bool
     227  msgdomain_equal (const msgdomain_ty *mdp1, const msgdomain_ty *mdp2,
     228                   bool ignore_potcdate)
     229  {
     230    return (strcmp (mdp1->domain, mdp2->domain) == 0
     231            && message_list_equal (mdp1->messages, mdp2->messages,
     232                                   ignore_potcdate));
     233  }
     234  
     235  bool
     236  msgdomain_list_equal (const msgdomain_list_ty *mdlp1,
     237                        const msgdomain_list_ty *mdlp2,
     238                        bool ignore_potcdate)
     239  {
     240    size_t i, i1, i2;
     241  
     242    i1 = mdlp1->nitems;
     243    i2 = mdlp2->nitems;
     244    if (i1 != i2)
     245      return false;
     246    for (i = 0; i < i1; i++)
     247      if (!msgdomain_equal (mdlp1->item[i], mdlp2->item[i], ignore_potcdate))
     248        return false;
     249    return true;
     250  }