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.
15 #define MAXLINELEN 1024
22 struct src
*src_from_file(char *filename
)
24 char line
[MAXLINELEN
];
25 struct line
*tail
= NULL
;
27 FILE *input
= fopen(filename
, "r");
28 struct src
*result
= xmalloc(sizeof(struct src
));
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
);
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
;
52 static long line_offset(struct src
*src
, int line
)
54 if (src
->invalid_from
<= line
) {
56 for (i
= src
->invalid_from
; i
<= line
; i
++)
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
));
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;
82 void src_free(struct src
*src
)
85 for (i
= 0; i
< src
->count
; i
++)
92 static int find_line(struct src
*src
, long offset
)
95 int end
= src
->count
- 1;
97 long mid
= (start
+ end
) / 2;
98 if (offset
< line_offset(src
, mid
))
100 else if (mid
< end
&& line_offset(src
, mid
+ 1) <= offset
)
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
)
143 for (cur
= start
; cur
< size
; cur
++)
145 return cur
- 3 < start
? start
: cur
- 3;
149 static int find_end(int start
, char *diffs
, int size
)
153 for (cur
= start
; cur
< size
; cur
++) {
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
;
169 printf("@@ -%d,%d +%d,%d @@\n", start
+ 1, len
,
172 printf("@@ -%d +%d @@\n", start
+ 1, start
+ 1);
173 for (; cur1
< end
; cur1
++) {
175 printf("-%s", src1
->lines
[cur1
]);
176 if (!diffs
[cur1
] || cur1
== end
- 1) {
177 for (; cur2
<= cur1
; cur2
++) {
179 printf("+%s", src2
->lines
[cur2
]);
181 printf(" %s", src2
->lines
[cur2
]);
187 static int init_diffs(struct src
*src1
, struct src
*src2
, char *diffs
)
191 for (i
= 0; i
< src1
->count
; i
++) {
192 diffs
[i
] = strcmp(src1
->lines
[i
], src2
->lines
[i
]);
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
);