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 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 31static inline bool 32msgstr_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 39static bool 40msgstr_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 110static inline bool 111pos_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 118bool 119string_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 133bool 134message_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 208bool 209message_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 224static inline bool 225msgdomain_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 233bool 234msgdomain_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