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