mirror of
https://github.com/git/git
synced 2024-07-16 10:38:05 +00:00
![Junio C Hamano](/assets/img/avatar_default.png)
Upon seeing a whitespace, xdl_hash_record_with_whitespace() first skipped the run of whitespaces (excluding LF) that begins there, ensuring that the pointer points at the last whitespace character in the run, and assumed that the next character must be LF at the end of the line. This does not work when hashing an incomplete line, which lacks the LF at the end. Introduce "at_eol" variable that is true when either we are at the end of line (looking at LF) or at the end of an incomplete line, and use that instead throughout the code. Noticed by Thell Fowler. Signed-off-by: Junio C Hamano <gitster@pobox.com>
385 lines
7.7 KiB
C
385 lines
7.7 KiB
C
/*
|
|
* LibXDiff by Davide Libenzi ( File Differential Library )
|
|
* Copyright (C) 2003 Davide Libenzi
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* Davide Libenzi <davidel@xmailserver.org>
|
|
*
|
|
*/
|
|
|
|
#include "xinclude.h"
|
|
|
|
|
|
|
|
#define XDL_GUESS_NLINES 256
|
|
|
|
|
|
|
|
|
|
long xdl_bogosqrt(long n) {
|
|
long i;
|
|
|
|
/*
|
|
* Classical integer square root approximation using shifts.
|
|
*/
|
|
for (i = 1; n > 0; n >>= 2)
|
|
i <<= 1;
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize,
|
|
xdemitcb_t *ecb) {
|
|
int i = 2;
|
|
mmbuffer_t mb[3];
|
|
|
|
mb[0].ptr = (char *) pre;
|
|
mb[0].size = psize;
|
|
mb[1].ptr = (char *) rec;
|
|
mb[1].size = size;
|
|
if (size > 0 && rec[size - 1] != '\n') {
|
|
mb[2].ptr = (char *) "\n\\ No newline at end of file\n";
|
|
mb[2].size = strlen(mb[2].ptr);
|
|
i++;
|
|
}
|
|
if (ecb->outf(ecb->priv, mb, i) < 0) {
|
|
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void *xdl_mmfile_first(mmfile_t *mmf, long *size)
|
|
{
|
|
*size = mmf->size;
|
|
return mmf->ptr;
|
|
}
|
|
|
|
|
|
void *xdl_mmfile_next(mmfile_t *mmf, long *size)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
long xdl_mmfile_size(mmfile_t *mmf)
|
|
{
|
|
return mmf->size;
|
|
}
|
|
|
|
|
|
int xdl_cha_init(chastore_t *cha, long isize, long icount) {
|
|
|
|
cha->head = cha->tail = NULL;
|
|
cha->isize = isize;
|
|
cha->nsize = icount * isize;
|
|
cha->ancur = cha->sncur = NULL;
|
|
cha->scurr = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void xdl_cha_free(chastore_t *cha) {
|
|
chanode_t *cur, *tmp;
|
|
|
|
for (cur = cha->head; (tmp = cur) != NULL;) {
|
|
cur = cur->next;
|
|
xdl_free(tmp);
|
|
}
|
|
}
|
|
|
|
|
|
void *xdl_cha_alloc(chastore_t *cha) {
|
|
chanode_t *ancur;
|
|
void *data;
|
|
|
|
if (!(ancur = cha->ancur) || ancur->icurr == cha->nsize) {
|
|
if (!(ancur = (chanode_t *) xdl_malloc(sizeof(chanode_t) + cha->nsize))) {
|
|
|
|
return NULL;
|
|
}
|
|
ancur->icurr = 0;
|
|
ancur->next = NULL;
|
|
if (cha->tail)
|
|
cha->tail->next = ancur;
|
|
if (!cha->head)
|
|
cha->head = ancur;
|
|
cha->tail = ancur;
|
|
cha->ancur = ancur;
|
|
}
|
|
|
|
data = (char *) ancur + sizeof(chanode_t) + ancur->icurr;
|
|
ancur->icurr += cha->isize;
|
|
|
|
return data;
|
|
}
|
|
|
|
|
|
void *xdl_cha_first(chastore_t *cha) {
|
|
chanode_t *sncur;
|
|
|
|
if (!(cha->sncur = sncur = cha->head))
|
|
return NULL;
|
|
|
|
cha->scurr = 0;
|
|
|
|
return (char *) sncur + sizeof(chanode_t) + cha->scurr;
|
|
}
|
|
|
|
|
|
void *xdl_cha_next(chastore_t *cha) {
|
|
chanode_t *sncur;
|
|
|
|
if (!(sncur = cha->sncur))
|
|
return NULL;
|
|
cha->scurr += cha->isize;
|
|
if (cha->scurr == sncur->icurr) {
|
|
if (!(sncur = cha->sncur = sncur->next))
|
|
return NULL;
|
|
cha->scurr = 0;
|
|
}
|
|
|
|
return (char *) sncur + sizeof(chanode_t) + cha->scurr;
|
|
}
|
|
|
|
|
|
long xdl_guess_lines(mmfile_t *mf) {
|
|
long nl = 0, size, tsize = 0;
|
|
char const *data, *cur, *top;
|
|
|
|
if ((cur = data = xdl_mmfile_first(mf, &size)) != NULL) {
|
|
for (top = data + size; nl < XDL_GUESS_NLINES;) {
|
|
if (cur >= top) {
|
|
tsize += (long) (cur - data);
|
|
if (!(cur = data = xdl_mmfile_next(mf, &size)))
|
|
break;
|
|
top = data + size;
|
|
}
|
|
nl++;
|
|
if (!(cur = memchr(cur, '\n', top - cur)))
|
|
cur = top;
|
|
else
|
|
cur++;
|
|
}
|
|
tsize += (long) (cur - data);
|
|
}
|
|
|
|
if (nl && tsize)
|
|
nl = xdl_mmfile_size(mf) / (tsize / nl);
|
|
|
|
return nl + 1;
|
|
}
|
|
|
|
int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
|
|
{
|
|
int i1, i2;
|
|
|
|
if (flags & XDF_IGNORE_WHITESPACE) {
|
|
for (i1 = i2 = 0; i1 < s1 && i2 < s2; ) {
|
|
if (isspace(l1[i1]))
|
|
while (isspace(l1[i1]) && i1 < s1)
|
|
i1++;
|
|
if (isspace(l2[i2]))
|
|
while (isspace(l2[i2]) && i2 < s2)
|
|
i2++;
|
|
if (i1 < s1 && i2 < s2 && l1[i1++] != l2[i2++])
|
|
return 0;
|
|
}
|
|
return (i1 >= s1 && i2 >= s2);
|
|
} else if (flags & XDF_IGNORE_WHITESPACE_CHANGE) {
|
|
for (i1 = i2 = 0; i1 < s1 && i2 < s2; ) {
|
|
if (isspace(l1[i1])) {
|
|
if (!isspace(l2[i2]))
|
|
return 0;
|
|
while (isspace(l1[i1]) && i1 < s1)
|
|
i1++;
|
|
while (isspace(l2[i2]) && i2 < s2)
|
|
i2++;
|
|
} else if (l1[i1++] != l2[i2++])
|
|
return 0;
|
|
}
|
|
return (i1 >= s1 && i2 >= s2);
|
|
} else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL) {
|
|
for (i1 = i2 = 0; i1 < s1 && i2 < s2; ) {
|
|
if (l1[i1] != l2[i2]) {
|
|
while (i1 < s1 && isspace(l1[i1]))
|
|
i1++;
|
|
while (i2 < s2 && isspace(l2[i2]))
|
|
i2++;
|
|
if (i1 < s1 || i2 < s2)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
i1++;
|
|
i2++;
|
|
}
|
|
return i1 >= s1 && i2 >= s2;
|
|
} else
|
|
return s1 == s2 && !memcmp(l1, l2, s1);
|
|
}
|
|
|
|
static unsigned long xdl_hash_record_with_whitespace(char const **data,
|
|
char const *top, long flags) {
|
|
unsigned long ha = 5381;
|
|
char const *ptr = *data;
|
|
|
|
for (; ptr < top && *ptr != '\n'; ptr++) {
|
|
if (isspace(*ptr)) {
|
|
const char *ptr2 = ptr;
|
|
int at_eol;
|
|
while (ptr + 1 < top && isspace(ptr[1])
|
|
&& ptr[1] != '\n')
|
|
ptr++;
|
|
at_eol = (top <= ptr + 1 || ptr[1] == '\n');
|
|
if (flags & XDF_IGNORE_WHITESPACE)
|
|
; /* already handled */
|
|
else if (flags & XDF_IGNORE_WHITESPACE_CHANGE
|
|
&& !at_eol) {
|
|
ha += (ha << 5);
|
|
ha ^= (unsigned long) ' ';
|
|
}
|
|
else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL
|
|
&& !at_eol) {
|
|
while (ptr2 != ptr + 1) {
|
|
ha += (ha << 5);
|
|
ha ^= (unsigned long) *ptr2;
|
|
ptr2++;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
ha += (ha << 5);
|
|
ha ^= (unsigned long) *ptr;
|
|
}
|
|
*data = ptr < top ? ptr + 1: ptr;
|
|
|
|
return ha;
|
|
}
|
|
|
|
|
|
unsigned long xdl_hash_record(char const **data, char const *top, long flags) {
|
|
unsigned long ha = 5381;
|
|
char const *ptr = *data;
|
|
|
|
if (flags & XDF_WHITESPACE_FLAGS)
|
|
return xdl_hash_record_with_whitespace(data, top, flags);
|
|
|
|
for (; ptr < top && *ptr != '\n'; ptr++) {
|
|
ha += (ha << 5);
|
|
ha ^= (unsigned long) *ptr;
|
|
}
|
|
*data = ptr < top ? ptr + 1: ptr;
|
|
|
|
return ha;
|
|
}
|
|
|
|
|
|
unsigned int xdl_hashbits(unsigned int size) {
|
|
unsigned int val = 1, bits = 0;
|
|
|
|
for (; val < size && bits < CHAR_BIT * sizeof(unsigned int); val <<= 1, bits++);
|
|
return bits ? bits: 1;
|
|
}
|
|
|
|
|
|
int xdl_num_out(char *out, long val) {
|
|
char *ptr, *str = out;
|
|
char buf[32];
|
|
|
|
ptr = buf + sizeof(buf) - 1;
|
|
*ptr = '\0';
|
|
if (val < 0) {
|
|
*--ptr = '-';
|
|
val = -val;
|
|
}
|
|
for (; val && ptr > buf; val /= 10)
|
|
*--ptr = "0123456789"[val % 10];
|
|
if (*ptr)
|
|
for (; *ptr; ptr++, str++)
|
|
*str = *ptr;
|
|
else
|
|
*str++ = '0';
|
|
*str = '\0';
|
|
|
|
return str - out;
|
|
}
|
|
|
|
|
|
long xdl_atol(char const *str, char const **next) {
|
|
long val, base;
|
|
char const *top;
|
|
|
|
for (top = str; XDL_ISDIGIT(*top); top++);
|
|
if (next)
|
|
*next = top;
|
|
for (val = 0, base = 1, top--; top >= str; top--, base *= 10)
|
|
val += base * (long)(*top - '0');
|
|
return val;
|
|
}
|
|
|
|
|
|
int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
|
|
const char *func, long funclen, xdemitcb_t *ecb) {
|
|
int nb = 0;
|
|
mmbuffer_t mb;
|
|
char buf[128];
|
|
|
|
memcpy(buf, "@@ -", 4);
|
|
nb += 4;
|
|
|
|
nb += xdl_num_out(buf + nb, c1 ? s1: s1 - 1);
|
|
|
|
if (c1 != 1) {
|
|
memcpy(buf + nb, ",", 1);
|
|
nb += 1;
|
|
|
|
nb += xdl_num_out(buf + nb, c1);
|
|
}
|
|
|
|
memcpy(buf + nb, " +", 2);
|
|
nb += 2;
|
|
|
|
nb += xdl_num_out(buf + nb, c2 ? s2: s2 - 1);
|
|
|
|
if (c2 != 1) {
|
|
memcpy(buf + nb, ",", 1);
|
|
nb += 1;
|
|
|
|
nb += xdl_num_out(buf + nb, c2);
|
|
}
|
|
|
|
memcpy(buf + nb, " @@", 3);
|
|
nb += 3;
|
|
if (func && funclen) {
|
|
buf[nb++] = ' ';
|
|
if (funclen > sizeof(buf) - nb - 1)
|
|
funclen = sizeof(buf) - nb - 1;
|
|
memcpy(buf + nb, func, funclen);
|
|
nb += funclen;
|
|
}
|
|
buf[nb++] = '\n';
|
|
|
|
mb.ptr = buf;
|
|
mb.size = nb;
|
|
if (ecb->outf(ecb->priv, &mb, 1) < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|