File Coverage

include/eshu_diff.h
Criterion Covered Total %
statement 81 95 85.2
branch 49 64 76.5
condition n/a
subroutine n/a
pod n/a
total 130 159 81.7


line stmt bran cond sub pod time code
1             /*
2             * eshu_diff.h — Simple unified-diff generator
3             *
4             * Pure C, no Perl dependencies.
5             */
6              
7             #ifndef ESHU_DIFF_H
8             #define ESHU_DIFF_H
9              
10             #include "eshu.h"
11             #include
12              
13             /* Generate a simple unified diff between old and new text.
14             * Returns a malloc'd string (caller must free). */
15 1           static char *eshu_simple_diff(const char *label,
16             const char *old_text, size_t old_len,
17             const char *new_text, size_t new_len,
18             size_t *out_len)
19             {
20             eshu_buf_t buf;
21             /* Split both into line arrays */
22 1           size_t old_cap = 256, new_cap = 256;
23 1           size_t old_count = 0, new_count = 0;
24             const char **old_lines, **new_lines;
25             size_t *old_lens, *new_lens;
26             const char *p;
27             size_t i, max, hunk_old_count, hunk_new_count;
28             int hunk_start;
29             /* Temp arrays for hunk lines */
30 1           size_t hunk_cap = 64;
31             size_t *ho_idx, *hn_idx;
32             char numbuf[64];
33              
34 1           eshu_buf_init(&buf, old_len > new_len ? old_len : new_len);
35              
36 1           old_lines = (const char **)malloc(old_cap * sizeof(const char *));
37 1           old_lens = (size_t *)malloc(old_cap * sizeof(size_t));
38 1           new_lines = (const char **)malloc(new_cap * sizeof(const char *));
39 1           new_lens = (size_t *)malloc(new_cap * sizeof(size_t));
40              
41             /* Parse old lines */
42 1           p = old_text;
43 4 100         while (p < old_text + old_len) {
44 3           const char *eol = p;
45 17 50         while (eol < old_text + old_len && *eol != '\n') eol++;
    100          
46 3 50         if (eol < old_text + old_len) eol++; /* include the newline */
47 3 50         if (old_count >= old_cap) {
48 0           old_cap *= 2;
49 0           old_lines = (const char **)realloc(old_lines, old_cap * sizeof(const char *));
50 0           old_lens = (size_t *)realloc(old_lens, old_cap * sizeof(size_t));
51             }
52 3           old_lines[old_count] = p;
53 3           old_lens[old_count] = (size_t)(eol - p);
54 3           old_count++;
55 3           p = eol;
56             }
57              
58             /* Parse new lines */
59 1           p = new_text;
60 4 100         while (p < new_text + new_len) {
61 3           const char *eol = p;
62 18 50         while (eol < new_text + new_len && *eol != '\n') eol++;
    100          
63 3 50         if (eol < new_text + new_len) eol++;
64 3 50         if (new_count >= new_cap) {
65 0           new_cap *= 2;
66 0           new_lines = (const char **)realloc(new_lines, new_cap * sizeof(const char *));
67 0           new_lens = (size_t *)realloc(new_lens, new_cap * sizeof(size_t));
68             }
69 3           new_lines[new_count] = p;
70 3           new_lens[new_count] = (size_t)(eol - p);
71 3           new_count++;
72 3           p = eol;
73             }
74              
75             /* Header */
76 1           eshu_buf_write(&buf, "--- a/", 6);
77 1           eshu_buf_write(&buf, label, strlen(label));
78 1           eshu_buf_putc(&buf, '\n');
79 1           eshu_buf_write(&buf, "+++ b/", 6);
80 1           eshu_buf_write(&buf, label, strlen(label));
81 1           eshu_buf_putc(&buf, '\n');
82              
83 1           ho_idx = (size_t *)malloc(hunk_cap * sizeof(size_t));
84 1           hn_idx = (size_t *)malloc(hunk_cap * sizeof(size_t));
85              
86 1           max = old_count > new_count ? old_count : new_count;
87 1           hunk_start = -1;
88 1           hunk_old_count = 0;
89 1           hunk_new_count = 0;
90              
91 5 100         for (i = 0; i <= max; i++) {
92 4           int same = 0;
93 4 100         if (i < old_count && i < new_count
    50          
94 3 100         && old_lens[i] == new_lens[i]
95 2 50         && memcmp(old_lines[i], new_lines[i], old_lens[i]) == 0) {
96 2           same = 1;
97             }
98              
99 4 100         if (!same && hunk_start < 0) {
    50          
100 2           hunk_start = (int)i;
101 2           hunk_old_count = 0;
102 2           hunk_new_count = 0;
103             }
104 4 100         if (hunk_start >= 0 && !same) {
    100          
105 2 100         if (i < old_count) {
106 1 50         if (hunk_old_count >= hunk_cap) {
107 0           hunk_cap *= 2;
108 0           ho_idx = (size_t *)realloc(ho_idx, hunk_cap * sizeof(size_t));
109 0           hn_idx = (size_t *)realloc(hn_idx, hunk_cap * sizeof(size_t));
110             }
111 1           ho_idx[hunk_old_count++] = i;
112             }
113 2 100         if (i < new_count) {
114 1 50         if (hunk_new_count >= hunk_cap) {
115 0           hunk_cap *= 2;
116 0           ho_idx = (size_t *)realloc(ho_idx, hunk_cap * sizeof(size_t));
117 0           hn_idx = (size_t *)realloc(hn_idx, hunk_cap * sizeof(size_t));
118             }
119 1           hn_idx[hunk_new_count++] = i;
120             }
121             }
122 4 100         if (same || i == max) {
    100          
123 3 100         if (hunk_start >= 0) {
124             size_t j;
125 2           int len = sprintf(numbuf, "@@ -%d,%d +%d,%d @@\n",
126             hunk_start + 1, (int)hunk_old_count,
127             hunk_start + 1, (int)hunk_new_count);
128 2           eshu_buf_write(&buf, numbuf, (size_t)len);
129 3 100         for (j = 0; j < hunk_old_count; j++) {
130 1           size_t idx = ho_idx[j];
131 1           eshu_buf_putc(&buf, '-');
132 1           eshu_buf_write(&buf, old_lines[idx], old_lens[idx]);
133 1 50         if (old_lens[idx] == 0 || old_lines[idx][old_lens[idx]-1] != '\n')
    50          
134 0           eshu_buf_putc(&buf, '\n');
135             }
136 3 100         for (j = 0; j < hunk_new_count; j++) {
137 1           size_t idx = hn_idx[j];
138 1           eshu_buf_putc(&buf, '+');
139 1           eshu_buf_write(&buf, new_lines[idx], new_lens[idx]);
140 1 50         if (new_lens[idx] == 0 || new_lines[idx][new_lens[idx]-1] != '\n')
    50          
141 0           eshu_buf_putc(&buf, '\n');
142             }
143 2           hunk_start = -1;
144             }
145             }
146             }
147              
148 1           free(ho_idx);
149 1           free(hn_idx);
150 1           free(old_lines);
151 1           free(old_lens);
152 1           free(new_lines);
153 1           free(new_lens);
154              
155 1           *out_len = buf.len;
156 1           return buf.data;
157             }
158              
159             #endif /* ESHU_DIFF_H */