|
|
Return nonzero if the lines differ. */ | Return nonzero if the lines differ. */ |
| |
bool | bool |
lines_differ (char const *s1, char const *s2) |
lines_differ_singlebyte (char const *s1, char const *s2) |
{ | { |
register char const *t1 = s1; | register char const *t1 = s1; |
register char const *t2 = s2; | register char const *t2 = s2; |
|
|
| |
return true; | return true; |
} | } |
|
|
|
|
|
#ifdef HANDLE_MULTIBYTE |
|
# define MBC2WC(T, END, MBLENGTH, WC, STATE, CONVFAIL) \ |
|
do \ |
|
{ \ |
|
mbstate_t bak = STATE; \ |
|
\ |
|
CONVFAIL = 0; \ |
|
MBLENGTH = mbrtowc (&WC, T, END - T, &STATE); \ |
|
\ |
|
switch (MBLENGTH) \ |
|
{ \ |
|
case (size_t)-2: \ |
|
case (size_t)-1: \ |
|
STATE = bak; \ |
|
++CONVFAIL; \ |
|
/* Fall through. */ \ |
|
case 0: \ |
|
MBLENGTH = 1; \ |
|
} \ |
|
} \ |
|
while (0) |
|
|
|
bool |
|
lines_differ_multibyte (char const *s1, char const *s2) |
|
{ |
|
unsigned char const *end1, *end2; |
|
unsigned char c1, c2; |
|
wchar_t wc1, wc2, wc1_bak, wc2_bak; |
|
size_t mblen1, mblen2; |
|
mbstate_t state1, state2, state1_bak, state2_bak; |
|
int convfail1, convfail2, convfail1_bak, convfail2_bak; |
|
|
|
unsigned char const *t1 = (unsigned char const *) s1; |
|
unsigned char const *t2 = (unsigned char const *) s2; |
|
unsigned char const *t1_bak, *t2_bak; |
|
size_t column = 0; |
|
|
|
if (ignore_white_space == IGNORE_NO_WHITE_SPACE && !ignore_case) |
|
{ |
|
while (*t1 != '\n') |
|
if (*t1++ != * t2++) |
|
return 1; |
|
return 0; |
|
} |
|
|
|
memset (&state1, '\0', sizeof (mbstate_t)); |
|
memset (&state2, '\0', sizeof (mbstate_t)); |
|
|
|
end1 = s1 + strlen (s1); |
|
end2 = s2 + strlen (s2); |
|
|
|
while (1) |
|
{ |
|
c1 = *t1; |
|
c2 = *t2; |
|
MBC2WC (t1, end1, mblen1, wc1, state1, convfail1); |
|
MBC2WC (t2, end2, mblen2, wc2, state2, convfail2); |
|
|
|
/* Test for exact char equality first, since it's a common case. */ |
|
if (convfail1 ^ convfail2) |
|
break; |
|
else if (convfail1 && convfail2 && c1 != c2) |
|
break; |
|
else if (!convfail1 && !convfail2 && wc1 != wc2) |
|
{ |
|
switch (ignore_white_space) |
|
{ |
|
case IGNORE_ALL_SPACE: |
|
/* For -w, just skip past any white space. */ |
|
while (1) |
|
{ |
|
if (convfail1) |
|
break; |
|
else if (wc1 == L'\n' || !iswspace (wc1)) |
|
break; |
|
|
|
t1 += mblen1; |
|
c1 = *t1; |
|
MBC2WC (t1, end1, mblen1, wc1, state1, convfail1); |
|
} |
|
|
|
while (1) |
|
{ |
|
if (convfail2) |
|
break; |
|
else if (wc2 == L'\n' || !iswspace (wc2)) |
|
break; |
|
|
|
t2 += mblen2; |
|
c2 = *t2; |
|
MBC2WC (t2, end2, mblen2, wc2, state2, convfail2); |
|
} |
|
t1 += mblen1; |
|
t2 += mblen2; |
|
break; |
|
|
|
case IGNORE_SPACE_CHANGE: |
|
/* For -b, advance past any sequence of white space in |
|
line 1 and consider it just one space, or nothing at |
|
all if it is at the end of the line. */ |
|
if (wc1 != L'\n' && iswspace (wc1)) |
|
{ |
|
size_t mblen_bak; |
|
mbstate_t state_bak; |
|
|
|
do |
|
{ |
|
t1 += mblen1; |
|
mblen_bak = mblen1; |
|
state_bak = state1; |
|
MBC2WC (t1, end1, mblen1, wc1, state1, convfail1); |
|
} |
|
while (!convfail1 && (wc1 != L'\n' && iswspace (wc1))); |
|
|
|
state1 = state_bak; |
|
mblen1 = mblen_bak; |
|
t1 -= mblen1; |
|
convfail1 = 0; |
|
wc1 = L' '; |
|
} |
|
|
|
/* Likewise for line 2. */ |
|
if (wc2 != L'\n' && iswspace (wc2)) |
|
{ |
|
size_t mblen_bak; |
|
mbstate_t state_bak; |
|
|
|
do |
|
{ |
|
t2 += mblen2; |
|
mblen_bak = mblen2; |
|
state_bak = state2; |
|
MBC2WC (t2, end2, mblen2, wc2, state2, convfail2); |
|
} |
|
while (!convfail2 && (wc2 != L'\n' && iswspace (wc2))); |
|
|
|
state2 = state_bak; |
|
mblen2 = mblen_bak; |
|
t2 -= mblen2; |
|
convfail2 = 0; |
|
wc2 = L' '; |
|
} |
|
|
|
if (wc1 != wc2) |
|
{ |
|
if (wc2 == L' ' && wc1 != L'\n' && |
|
t1 > (unsigned char const *)s1 && |
|
!convfail1_bak && iswspace (wc1_bak)) |
|
{ |
|
t1 = t1_bak; |
|
wc1 = wc1_bak; |
|
state1 = state1_bak; |
|
convfail1 = convfail1_bak; |
|
continue; |
|
} |
|
if (wc1 == L' ' && wc2 != L'\n' |
|
&& t2 > (unsigned char const *)s2 |
|
&& !convfail2_bak && iswspace (wc2_bak)) |
|
{ |
|
t2 = t2_bak; |
|
wc2 = wc2_bak; |
|
state2 = state2_bak; |
|
convfail2 = convfail2_bak; |
|
continue; |
|
} |
|
} |
|
|
|
t1_bak = t1; t2_bak = t2; |
|
wc1_bak = wc1; wc2_bak = wc2; |
|
state1_bak = state1; state2_bak = state2; |
|
convfail1_bak = convfail1; convfail2_bak = convfail2; |
|
|
|
if (wc1 == L'\n') |
|
wc1 = L' '; |
|
else |
|
t1 += mblen1; |
|
|
|
if (wc2 == L'\n') |
|
wc2 = L' '; |
|
else |
|
t2 += mblen2; |
|
|
|
break; |
|
|
|
case IGNORE_TAB_EXPANSION: |
|
if ((wc1 == L' ' && wc2 == L'\t') |
|
|| (wc1 == L'\t' && wc2 == L' ')) |
|
{ |
|
size_t column2 = column; |
|
|
|
while (1) |
|
{ |
|
if (convfail1) |
|
{ |
|
++t1; |
|
break; |
|
} |
|
else if (wc1 == L' ') |
|
column++; |
|
else if (wc1 == L'\t') |
|
column += TAB_WIDTH - column % TAB_WIDTH; |
|
else |
|
{ |
|
t1 += mblen1; |
|
break; |
|
} |
|
|
|
t1 += mblen1; |
|
c1 = *t1; |
|
MBC2WC (t1, end1, mblen1, wc1, state1, convfail1); |
|
} |
|
|
|
while (1) |
|
{ |
|
if (convfail2) |
|
{ |
|
++t2; |
|
break; |
|
} |
|
else if (wc2 == L' ') |
|
column2++; |
|
else if (wc2 == L'\t') |
|
column2 += TAB_WIDTH - column2 % TAB_WIDTH; |
|
else |
|
{ |
|
t2 += mblen2; |
|
break; |
|
} |
|
|
|
t2 += mblen2; |
|
c2 = *t2; |
|
MBC2WC (t2, end2, mblen2, wc2, state2, convfail2); |
|
} |
|
|
|
if (column != column2) |
|
return 1; |
|
} |
|
else |
|
{ |
|
t1 += mblen1; |
|
t2 += mblen2; |
|
} |
|
break; |
|
|
|
case IGNORE_NO_WHITE_SPACE: |
|
t1 += mblen1; |
|
t2 += mblen2; |
|
break; |
|
} |
|
|
|
/* Lowercase all letters if -i is specified. */ |
|
if (ignore_case) |
|
{ |
|
if (!convfail1) |
|
wc1 = towlower (wc1); |
|
if (!convfail2) |
|
wc2 = towlower (wc2); |
|
} |
|
|
|
if (convfail1 ^ convfail2) |
|
break; |
|
else if (convfail1 && convfail2 && c1 != c2) |
|
break; |
|
else if (!convfail1 && !convfail2 && wc1 != wc2) |
|
break; |
|
} |
|
else |
|
{ |
|
t1_bak = t1; t2_bak = t2; |
|
wc1_bak = wc1; wc2_bak = wc2; |
|
state1_bak = state1; state2_bak = state2; |
|
convfail1_bak = convfail1; convfail2_bak = convfail2; |
|
|
|
t1 += mblen1; t2 += mblen2; |
|
} |
|
|
|
if (!convfail1 && wc1 == L'\n') |
|
return 0; |
|
|
|
column += convfail1 ? 1 : |
|
(wc1 == L'\t') ? TAB_WIDTH - column % TAB_WIDTH : wcwidth (wc1); |
|
} |
|
|
|
return 1; |
|
} |
|
#endif |
| |
/* Find the consecutive changes at the start of the script START. | /* Find the consecutive changes at the start of the script START. |
Return the last link before the first gap. */ | Return the last link before the first gap. */ |