Imported Upstream version 0.18.1.1
[platform/upstream/gettext.git] / 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 <http://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 }