1/* Message list test for equality. 2 Copyright (C) 2001-2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 (strcmp (mp1->msgid, mp2->msgid) != 0) 140 return false; 141 142 if (!(mp1->msgid_plural != NULL 143 ? mp2->msgid_plural != NULL 144 && strcmp (mp1->msgid_plural, mp2->msgid_plural) == 0 145 : mp2->msgid_plural == NULL)) 146 return false; 147 148 if (mp1->msgid[0] == '\0' && ignore_potcdate 149 ? !msgstr_equal_ignoring_potcdate (mp1->msgstr, mp1->msgstr_len, 150 mp2->msgstr, mp2->msgstr_len) 151 : !msgstr_equal (mp1->msgstr, mp1->msgstr_len, 152 mp2->msgstr, mp2->msgstr_len)) 153 return false; 154 155 if (!pos_equal (&mp1->pos, &mp2->pos)) 156 return false; 157 158 if (!string_list_equal (mp1->comment, mp2->comment)) 159 return false; 160 161 if (!string_list_equal (mp1->comment_dot, mp2->comment_dot)) 162 return false; 163 164 i1 = mp1->filepos_count; 165 i2 = mp2->filepos_count; 166 if (i1 != i2) 167 return false; 168 for (i = 0; i < i1; i++) 169 if (!pos_equal (&mp1->filepos[i], &mp2->filepos[i])) 170 return false; 171 172 if (mp1->is_fuzzy != mp2->is_fuzzy) 173 return false; 174 175 for (i = 0; i < NFORMATS; i++) 176 if (mp1->is_format[i] != mp2->is_format[i]) 177 return false; 178 179 if (mp1->obsolete != mp2->obsolete) 180 return false; 181 182 return true; 183} 184 185bool 186message_list_equal (const message_list_ty *mlp1, const message_list_ty *mlp2, 187 bool ignore_potcdate) 188{ 189 size_t i, i1, i2; 190 191 i1 = mlp1->nitems; 192 i2 = mlp2->nitems; 193 if (i1 != i2) 194 return false; 195 for (i = 0; i < i1; i++) 196 if (!message_equal (mlp1->item[i], mlp2->item[i], ignore_potcdate)) 197 return false; 198 return true; 199} 200 201static inline bool 202msgdomain_equal (const msgdomain_ty *mdp1, const msgdomain_ty *mdp2, 203 bool ignore_potcdate) 204{ 205 return (strcmp (mdp1->domain, mdp2->domain) == 0 206 && message_list_equal (mdp1->messages, mdp2->messages, 207 ignore_potcdate)); 208} 209 210bool 211msgdomain_list_equal (const msgdomain_list_ty *mdlp1, 212 const msgdomain_list_ty *mdlp2, 213 bool ignore_potcdate) 214{ 215 size_t i, i1, i2; 216 217 i1 = mdlp1->nitems; 218 i2 = mdlp2->nitems; 219 if (i1 != i2) 220 return false; 221 for (i = 0; i < i1; i++) 222 if (!msgdomain_equal (mdlp1->item[i], mdlp2->item[i], ignore_potcdate)) 223 return false; 224 return true; 225} 226