block: don't put spaces around :
[ironout.git] / src.c
blob4e6d0f67c4880ca55c605d6782cb7a4f8d76856d
1 /*
2 * src.c - calculate source code changes
4 * Copyright (C) 2008 Ali Gholami Rudi
6 * Currently inserts and deletes don't span many lines; that makes
7 * src_insert(), src_delete() and src_print_diffs() much simpler.
8 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include "src.h"
13 #include "utils.h"
15 #define MAXLINELEN 1024
17 struct line {
18 char *line;
19 struct line *next;
22 struct src *src_from_file(char *filename)
24 char line[MAXLINELEN];
25 struct line *tail = NULL;
26 int count = 0;
27 FILE *input = fopen(filename, "r");
28 struct src *result = xmalloc(sizeof(struct src));
29 int i;
31 while (fgets(line, MAXLINELEN, input)) {
32 struct line *cur = xmalloc(sizeof(struct line));
33 cur->line = xmalloc(strlen(line) + 1);
34 strcpy(cur->line, line);
35 cur->next = tail;
36 tail = cur;
37 count++;
39 result->count = count;
40 result->lines = xmalloc(sizeof(char *) * count);
41 result->offsets = xmalloc(sizeof(long) * count);
42 result->invalid_from = 0;
43 for (i = count - 1; i >= 0; i--) {
44 struct line *next = tail->next;
45 result->lines[i] = tail->line;
46 free(tail);
47 tail = next;
49 return result;
52 static long line_offset(struct src *src, int line)
54 if (src->invalid_from <= line) {
55 int i;
56 for (i = src->invalid_from; i <= line; i++)
57 if (!i)
58 src->offsets[i] = 0;
59 else
60 src->offsets[i] = src->offsets[i - 1] +
61 strlen(src->lines[i - 1]);
62 src->invalid_from = line + 1;
64 return src->offsets[line];
67 struct src *src_copy(struct src *src)
69 struct src *result = xmalloc(sizeof(struct src));
70 int i;
71 result->count = src->count;
72 result->lines = xmalloc(sizeof(char *) * src->count);
73 result->offsets = xmalloc(sizeof(long) * src->count);
74 for (i = 0; i < src->count; i++) {
75 result->lines[i] = xmalloc(strlen(src->lines[i]) + 1);
76 strcpy(result->lines[i], src->lines[i]);
78 result->invalid_from = 0;
79 return result;
82 void src_free(struct src *src)
84 int i;
85 for (i = 0; i < src->count; i++)
86 free(src->lines[i]);
87 free(src->lines);
88 free(src->offsets);
89 free(src);
92 static int find_line(struct src *src, long offset)
94 int start = 0;
95 int end = src->count - 1;
96 while (start < end) {
97 long mid = (start + end) / 2;
98 if (offset < line_offset(src, mid))
99 end = mid - 1;
100 else if (mid < end && line_offset(src, mid + 1) <= offset)
101 start = mid + 1;
102 else
103 return mid;
105 return start;
108 void src_delete(struct src *src, long from, long to)
110 int lineno = find_line(src, from);
111 char *newline = xmalloc(strlen(src->lines[lineno]) - (to - from) + 1);
112 long before = from - line_offset(src, lineno);
113 long after = to - line_offset(src, lineno);
114 memcpy(newline, src->lines[lineno], before);
115 strcpy(newline + before, src->lines[lineno] + after);
116 free(src->lines[lineno]);
117 src->lines[lineno] = newline;
118 src->invalid_from = lineno;
121 void src_insert(struct src *src, long offset, char *s)
123 int lineno = find_line(src, offset);
124 char *newline = xmalloc(strlen(src->lines[lineno]) + strlen(s) + 1);
125 long point = offset - line_offset(src, lineno);
126 memcpy(newline, src->lines[lineno], point);
127 strcpy(newline + point, s);
128 strcpy(newline + point + strlen(s), src->lines[lineno] + point);
129 free(src->lines[lineno]);
130 src->lines[lineno] = newline;
131 src->invalid_from = lineno;
134 static void print_diff_header(char *filename)
136 printf("diff --git a/%s b/%s\n--- a/%s\n+++ b/%s\n",
137 filename, filename, filename, filename);
140 static int find_start(int start, char *diffs, int size)
142 int cur;
143 for (cur = start; cur < size; cur++)
144 if (diffs[cur])
145 return cur - 3 < start ? start : cur - 3;
146 return -1;
149 static int find_end(int start, char *diffs, int size)
151 int cur;
152 int ones = 0;
153 for (cur = start; cur < size; cur++) {
154 ones++;
155 if (diffs[cur])
156 ones = 0;
157 if (ones == 7)
158 return cur - 3 < start ? start : cur - 3;
160 return ones < 3 ? size : size + 3 - ones;
163 static void print_hunk(struct src *src1, struct src *src2,
164 char *diffs, int start, int end)
166 int cur1 = start, cur2 = start;
167 int len = end - start;
168 if (len > 1)
169 printf("@@ -%d,%d +%d,%d @@\n", start + 1, len,
170 start + 1, len);
171 else
172 printf("@@ -%d +%d @@\n", start + 1, start + 1);
173 for (; cur1 < end; cur1++) {
174 if (diffs[cur1])
175 printf("-%s", src1->lines[cur1]);
176 if (!diffs[cur1] || cur1 == end - 1) {
177 for (; cur2 <= cur1; cur2++) {
178 if (diffs[cur2])
179 printf("+%s", src2->lines[cur2]);
180 else
181 printf(" %s", src2->lines[cur2]);
187 static int init_diffs(struct src *src1, struct src *src2, char *diffs)
189 int differs = 0;
190 int i;
191 for (i = 0; i < src1->count; i++) {
192 diffs[i] = strcmp(src1->lines[i], src2->lines[i]);
193 if (diffs[i])
194 differs = 1;
196 return differs;
199 void src_print_diffs(struct src *src1, struct src *src2, char *filename)
201 char *diffs = xmalloc(src1->count);
202 int start = 0, end = 0;
203 if (init_diffs(src1, src2, diffs)) {
204 print_diff_header(filename);
205 while ((start = find_start(end, diffs, src1->count)) >= 0) {
206 end = find_end(start, diffs, src1->count);
207 print_hunk(src1, src2, diffs, start, end);
210 free(diffs);