Skip to content

Commit 994e902

Browse files
authored
Merge pull request #2 from diasbruno/feature/first-implementation.
First implementation.
2 parents 99610b3 + e8f3fad commit 994e902

File tree

10 files changed

+396
-0
lines changed

10 files changed

+396
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*.o
2+
*.a
3+
tests/tests

include/diffstats/diffstats.h

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#ifndef __DIFFSTATS_H__
2+
#define __DIFFSTATS_H__ 1
3+
4+
enum diff_stats_err_t {
5+
HUNK_WITHOUT_DIFF = 1
6+
};
7+
8+
struct diff_stats_t {
9+
long starts_at;
10+
long count;
11+
long hunks;
12+
long* hunks_at;
13+
};
14+
15+
/**
16+
* From the current point in text, is there a `diff`?
17+
* @param {char*} text - the string.
18+
* @param {long} column - text column (updated every new line).
19+
* @return {int}
20+
*/
21+
int diff_stats_is_diff_header(const char* text, long column);
22+
23+
/**
24+
* From the current point in text, is there a `@@`?
25+
* @param {char*} text - the string.
26+
* @param {long} column - text column (updated every new line).
27+
* @return {int}
28+
*/
29+
int diff_stats_is_hunk_header(const char* text, long column);
30+
31+
/**
32+
* Add a found hunk to the list.
33+
* @param {struct diff_stats_t*} d - diff stats object.
34+
* @param {long} i - index in the text where it was found.
35+
* @return {void}
36+
*/
37+
void diff_stats_add_hunk_at(struct diff_stats_t* d, long i);
38+
39+
/**
40+
* Print all matches.
41+
* @param {struct diff_stats_t*} d - diff stats object.
42+
* @param {long} count - number of diffs.
43+
* @return {void}
44+
*/
45+
void diff_stats_print_list(struct diff_stats_t* d, long count);
46+
47+
/**
48+
* Print the state of the object.
49+
* @param {struct diff_stats_t*} d - diff stats object.
50+
* @return {void}
51+
*/
52+
void diff_stats_print(struct diff_stats_t* d);
53+
54+
/**
55+
* Free the object.
56+
* @param {struct diff_stats_t*} d - diff stats object.
57+
* @param {long} count - number of diffs.
58+
* @return {void}
59+
*/
60+
void diff_stats_free(struct diff_stats_t* d, long count);
61+
62+
/**
63+
* Parse a string.
64+
* @param {char*} str - reference to the string.
65+
* @param {long*} counter - [out] number of found diffs.
66+
* @param {int*} err - [out] error status.
67+
* @return {struct diff_stats_t*}
68+
*/
69+
struct diff_stats_t* diff_stats_parser(const char* str, long* counter, int* err);
70+
71+
#endif // __DIFFSTATS_H__

license.md

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2016 Bruno Dias.
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is
8+
furnished to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19+
SOFTWARE.

makefile

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
MAKE=$(shell which make)
2+
3+
build-src:
4+
$(MAKE) -C src -f makefile all
5+
6+
build-lib: build-src
7+
ar cr libdiffstats.a $(wildcard src/*.o)
8+
9+
build-tests: build-lib
10+
$(MAKE) -C tests -f makefile all
11+
12+
clean-src:
13+
$(MAKE) -C src -f makefile clean
14+
15+
clean-tests:
16+
$(MAKE) -C tests -f makefile clean
17+
18+
clean: clean-src clean-tests
19+
rm -rf libdiffstats.a
20+
21+
build: build-lib
22+
23+
run-tests:
24+
$(MAKE) -C tests -f makefile run
25+
26+
all: build-lib build-tests

readme.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# diffstats
2+
3+
Not the `diffstat(1)`.
4+
5+
This should find all diffs in a text and list all hunks available.
6+
7+
This tool can be used to get information in a diff text.

src/diffstats.c

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
#include <diffstats/diffstats.h>
5+
6+
static struct diff_stats_t* diff_stats_prepare_item(struct diff_stats_t* d) {
7+
d->starts_at = -1;
8+
d->count = 0;
9+
d->hunks = 10;
10+
d->hunks_at = (long*)malloc(sizeof(long) * 10);
11+
memset(d->hunks_at, 0, sizeof(long) * 10);
12+
return d;
13+
}
14+
15+
int diff_stats_is_diff_header(const char* text, long column) {
16+
return *text == 'd' && strncmp(text, (char*)"diff", 4) == 0 && column == 0;
17+
}
18+
19+
int diff_stats_is_hunk_header(const char* text, long column) {
20+
return *text == '@' && strncmp(text, (char*)"@@", 2) == 0 && column == 0;
21+
}
22+
23+
void diff_stats_add_hunk_at(struct diff_stats_t* d, long i) {
24+
if (d->count + 1 == d->hunks) {
25+
d->hunks = d->hunks + 10;
26+
d->hunks_at = (long*)realloc(d->hunks_at, sizeof(long) * d->hunks);
27+
}
28+
d->hunks_at[d->count] = i;
29+
d->count += 1;
30+
}
31+
32+
void diff_stats_print_list(struct diff_stats_t* d, long count) {
33+
printf("-> print base %p\n", d);
34+
for (int i = 0; i < count; i++) {
35+
printf("-> print item %p\n", &d[i]);
36+
diff_stats_print(&d[i]);
37+
}
38+
}
39+
40+
void diff_stats_print(struct diff_stats_t* d) {
41+
printf("diff starts at %ld with %ld hunk(s).\n",
42+
d->starts_at,
43+
d->count);
44+
for (int j = 0; j < d->count; j++) {
45+
printf("hunk at %ld\n", d->hunks_at[j]);
46+
}
47+
}
48+
49+
void diff_stats_free(struct diff_stats_t* d, long count) {
50+
for (int i = 0 ; i < count; i++) {
51+
free(d[i].hunks_at);
52+
}
53+
free(d);
54+
}
55+
56+
struct diff_stats_t* diff_stats_parser(const char* str, long* counter, int* err) {
57+
char* hold = (char*)str;
58+
char* text = hold;
59+
long column = 0;
60+
long index = 0;
61+
long count = 12;
62+
struct diff_stats_t* diff =
63+
(struct diff_stats_t*)malloc(sizeof(struct diff_stats_t) * count);
64+
struct diff_stats_t* head = NULL;
65+
66+
while (*text) {
67+
if (diff_stats_is_diff_header(text, column)) {
68+
if (index + 1 <= count) {
69+
count += 12;
70+
diff = (struct diff_stats_t*)realloc(diff, sizeof(struct diff_stats_t) * count);
71+
}
72+
head = diff_stats_prepare_item(diff + index);
73+
head->starts_at = (long)(text - hold);
74+
index++;
75+
}
76+
77+
if (diff_stats_is_hunk_header(text, column)) {
78+
if (!head) {
79+
*err = HUNK_WITHOUT_DIFF;
80+
free(diff);
81+
diff = NULL;
82+
goto diff_stats_end;
83+
}
84+
diff_stats_add_hunk_at(head, (long)(text - hold));
85+
}
86+
87+
if (*text == '\n') {
88+
column = 0;
89+
} else {
90+
column++;
91+
}
92+
++text;
93+
}
94+
95+
*err = 0;
96+
*counter = index;
97+
98+
diff_stats_end:
99+
100+
return diff;
101+
}

src/makefile

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CX=clang
2+
CXX=$(CX)++
3+
4+
CFLAGS=-Wall -Werror -std=c99 -g
5+
6+
SOURCES=$(wildcard *.c)
7+
OBJECTS=$(SOURCES:%.c=%.o)
8+
9+
INCLUDES=-I../include
10+
11+
include ../tools/helpers.mk
12+
13+
all: $(OBJECTS)
14+
15+
clean:
16+
rm -rf $(OBJECTS)

tests/main.c

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
#include <assert.h>
5+
#include <diffstats/diffstats.h>
6+
7+
static void test_check_for_diff_header(void) {
8+
int ok = diff_stats_is_diff_header("diff", 0);
9+
assert(ok);
10+
int fail = !diff_stats_is_diff_header("diff", 1);
11+
assert(fail);
12+
}
13+
14+
static void test_check_for_hunk_header(void) {
15+
int ok = diff_stats_is_hunk_header("@@", 0);
16+
assert(ok);
17+
int fail = !diff_stats_is_hunk_header("@@", 1);
18+
assert(fail);
19+
}
20+
21+
static void test_simple(void) {
22+
static char* const diff_simple_test =
23+
"diff --git a/page b/page\n"
24+
"--- a/page\n"
25+
"+++ b/page\n"
26+
"@@ -1,1 +1,1 @@\n"
27+
"-test\n"
28+
"+test 2\n";
29+
30+
printf("\ntesting\n%s\n", diff_simple_test);
31+
long count = 0;
32+
int err = 0;
33+
struct diff_stats_t* st = diff_stats_parser(diff_simple_test, &count, &err);
34+
assert(st[0].starts_at == 0);
35+
assert(st[0].count == 1);
36+
free(st);
37+
}
38+
39+
static void test_with_2_hunks(void) {
40+
static char* const diff_with_2_hunks_test =
41+
"diff --git a/page b/page\n"
42+
"--- a/page\n"
43+
"+++ b/page\n"
44+
"@@ -1,8 +1,8 @@\n"
45+
"-test 3\n"
46+
"+test 3 iasdf\n"
47+
"\n"
48+
"\n"
49+
"\n"
50+
"-test 2\n"
51+
"+test 2 asdfasdf\n"
52+
"\n"
53+
"\n"
54+
"\n"
55+
"@@ -21,8 +21,8 @@\n"
56+
"\n"
57+
"asdasdfasdfasd\n"
58+
"\n"
59+
"-asdfasdf\n"
60+
"-asdfa\n"
61+
"+asdfasdfs dasfd\n"
62+
"+asdfa asdfasdf\n"
63+
"sdfa\n"
64+
"sdf\n"
65+
"asdf";
66+
67+
printf("\ntesting\n%s\n", diff_with_2_hunks_test);
68+
long count = 0;
69+
int err = 0;
70+
struct diff_stats_t* st = diff_stats_parser(diff_with_2_hunks_test, &count, &err);
71+
assert(st[0].starts_at == 0);
72+
assert(st[0].count == 2);
73+
free(st);
74+
}
75+
76+
static void test_mixed(void) {
77+
static const char* const diff_mixed_test =
78+
"diff --git a/page b/page\n"
79+
"--- a/page\n"
80+
"+++ b/page\n"
81+
"@@ -1,1 +1,1 @@\n"
82+
"-test\n"
83+
"+test 2\n"
84+
"diff --git a/page b/page\n"
85+
"--- a/page\n"
86+
"+++ b/page\n"
87+
"@@ -1,1 +1,1 @@\n"
88+
"-test\n"
89+
"+test 2\n";
90+
91+
printf("\ntesting\n%s\n", diff_mixed_test);
92+
long count = 0;
93+
int err = 0;
94+
struct diff_stats_t* st = diff_stats_parser(diff_mixed_test, &count, &err);
95+
assert(st[0].starts_at == 0);
96+
assert(st[0].count == 1);
97+
assert(st[1].starts_at == 77);
98+
assert(st[1].count == 1);
99+
free(st);
100+
}
101+
102+
static void test_hunk_without_diff(void) {
103+
static const char* const diff_hunk_without_diff_test =
104+
"@@ -1,1 +1,1 @@\n"
105+
"-test\n"
106+
"+test 2\n";
107+
108+
printf("\ntesting\n%s\n", diff_hunk_without_diff_test);
109+
long count = 0;
110+
int err = 0;
111+
struct diff_stats_t* st = diff_stats_parser(diff_hunk_without_diff_test, &count, &err);
112+
assert(st == NULL);
113+
assert(err == HUNK_WITHOUT_DIFF);
114+
}
115+
116+
int main(int argc, char* argv[]) {
117+
test_check_for_diff_header();
118+
test_check_for_hunk_header();
119+
test_simple();
120+
test_with_2_hunks();
121+
test_mixed();
122+
test_hunk_without_diff();
123+
return 0;
124+
}

tests/makefile

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
CX=clang
2+
CXX=$(CX)++
3+
4+
CFLAGS=-Wall -Werror -std=c99
5+
6+
SOURCES=$(wildcard *.c)
7+
OBJECTS=$(SOURCES:%.c=%.o)
8+
9+
INCLUDES=-I ../include
10+
11+
include ../tools/helpers.mk
12+
13+
tests: $(OBJECTS)
14+
$(CX) -MMD -MP -MF $@.d $(CFLAGS) $(INCLUDES) -o $@ $^ ../libdiffstats.a
15+
16+
-include tests.d
17+
18+
run:
19+
./tests
20+
21+
all: tests
22+
23+
clean:
24+
rm -rf $(OBJECTS) tests

0 commit comments

Comments
 (0)