Add -lm dependency for gettextlib to fix LTO build
[platform/upstream/gettext.git] / gettext-tools / src / msgl-equal.c
1 /* Message list test for equality.
2    Copyright (C) 2001-2002, 2005-2006, 2008, 2015 Free Software
3    Foundation, Inc.
4    Written by Bruno Haible <haible@clisp.cons.org>, 2001.
5
6    This program is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
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 = (const char *) 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 = (const char *) 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 = (const char *) memchr (ptr1, '\n', msgstr1_end - ptr1);
95               if (ptr1 == NULL)
96                 ptr1 = msgstr1_end;
97
98               ptr2 = (const char *) 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->range.min == mp2->range.min && mp1->range.max == mp2->range.max))
185     return false;
186
187   if (!(mp1->prev_msgctxt != NULL
188         ? mp2->prev_msgctxt != NULL
189           && strcmp (mp1->prev_msgctxt, mp2->prev_msgctxt) == 0
190         : mp2->prev_msgctxt == NULL))
191     return false;
192
193   if (!(mp1->prev_msgid != NULL
194         ? mp2->prev_msgid != NULL
195           && strcmp (mp1->prev_msgid, mp2->prev_msgid) == 0
196         : mp2->prev_msgid == NULL))
197     return false;
198
199   if (!(mp1->prev_msgid_plural != NULL
200         ? mp2->prev_msgid_plural != NULL
201           && strcmp (mp1->prev_msgid_plural, mp2->prev_msgid_plural) == 0
202         : mp2->prev_msgid_plural == NULL))
203     return false;
204
205   if (mp1->obsolete != mp2->obsolete)
206     return false;
207
208   return true;
209 }
210
211 bool
212 message_list_equal (const message_list_ty *mlp1, const message_list_ty *mlp2,
213                     bool ignore_potcdate)
214 {
215   size_t i, i1, i2;
216
217   i1 = mlp1->nitems;
218   i2 = mlp2->nitems;
219   if (i1 != i2)
220     return false;
221   for (i = 0; i < i1; i++)
222     if (!message_equal (mlp1->item[i], mlp2->item[i], ignore_potcdate))
223       return false;
224   return true;
225 }
226
227 static inline bool
228 msgdomain_equal (const msgdomain_ty *mdp1, const msgdomain_ty *mdp2,
229                  bool ignore_potcdate)
230 {
231   return (strcmp (mdp1->domain, mdp2->domain) == 0
232           && message_list_equal (mdp1->messages, mdp2->messages,
233                                  ignore_potcdate));
234 }
235
236 bool
237 msgdomain_list_equal (const msgdomain_list_ty *mdlp1,
238                       const msgdomain_list_ty *mdlp2,
239                       bool ignore_potcdate)
240 {
241   size_t i, i1, i2;
242
243   i1 = mdlp1->nitems;
244   i2 = mdlp2->nitems;
245   if (i1 != i2)
246     return false;
247   for (i = 0; i < i1; i++)
248     if (!msgdomain_equal (mdlp1->item[i], mdlp2->item[i], ignore_potcdate))
249       return false;
250   return true;
251 }