1/* Message list test for equality. 2 Copyright (C) 2001-2002, 2005-2006 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 30static inline bool 31msgstr_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 38static bool 39msgstr_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 109static inline bool 110pos_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 117bool 118string_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 132bool 133message_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->prev_msgctxt != NULL 184 ? mp2->prev_msgctxt != NULL 185 && strcmp (mp1->prev_msgctxt, mp2->prev_msgctxt) == 0 186 : mp2->prev_msgctxt == NULL)) 187 return false; 188 189 if (!(mp1->prev_msgid != NULL 190 ? mp2->prev_msgid != NULL 191 && strcmp (mp1->prev_msgid, mp2->prev_msgid) == 0 192 : mp2->prev_msgid == NULL)) 193 return false; 194 195 if (!(mp1->prev_msgid_plural != NULL 196 ? mp2->prev_msgid_plural != NULL 197 && strcmp (mp1->prev_msgid_plural, mp2->prev_msgid_plural) == 0 198 : mp2->prev_msgid_plural == NULL)) 199 return false; 200 201 if (mp1->obsolete != mp2->obsolete) 202 return false; 203 204 return true; 205} 206 207bool 208message_list_equal (const message_list_ty *mlp1, const message_list_ty *mlp2, 209 bool ignore_potcdate) 210{ 211 size_t i, i1, i2; 212 213 i1 = mlp1->nitems; 214 i2 = mlp2->nitems; 215 if (i1 != i2) 216 return false; 217 for (i = 0; i < i1; i++) 218 if (!message_equal (mlp1->item[i], mlp2->item[i], ignore_potcdate)) 219 return false; 220 return true; 221} 222 223static inline bool 224msgdomain_equal (const msgdomain_ty *mdp1, const msgdomain_ty *mdp2, 225 bool ignore_potcdate) 226{ 227 return (strcmp (mdp1->domain, mdp2->domain) == 0 228 && message_list_equal (mdp1->messages, mdp2->messages, 229 ignore_potcdate)); 230} 231 232bool 233msgdomain_list_equal (const msgdomain_list_ty *mdlp1, 234 const msgdomain_list_ty *mdlp2, 235 bool ignore_potcdate) 236{ 237 size_t i, i1, i2; 238 239 i1 = mdlp1->nitems; 240 i2 = mdlp2->nitems; 241 if (i1 != i2) 242 return false; 243 for (i = 0; i < i1; i++) 244 if (!msgdomain_equal (mdlp1->item[i], mdlp2->item[i], ignore_potcdate)) 245 return false; 246 return true; 247} 248