Blob


1 /*
2 * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
17 #include <sys/queue.h>
18 #include <sys/stat.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <sha1.h>
23 #include <zlib.h>
25 #include "got_object.h"
27 #include "got_error.h"
28 #include "got_lib_delta.h"
29 #include "got_lib_inflate.h"
30 #include "got_lib_object.h"
31 #include "got_lib_diffoffset.h"
33 /*
34 * A line offset between an old file and a new file, derived from diff chunk
35 * header info @@ -old_lineno,old_length +new_lineno,new_length @@ in a diff
36 * with zero context lines (as in diff -U0 old-file new-file).
37 */
38 struct got_diffoffset_chunk {
39 int lineno; /* first line which has shifted */
40 int offset; /* applies to subsequent lines until next chunk */
41 SIMPLEQ_ENTRY(got_diffoffset_chunk) entry;
42 };
44 static struct got_diffoffset_chunk *
45 alloc_chunk(int lineno, int offset)
46 {
47 struct got_diffoffset_chunk *chunk;
49 chunk = calloc(1, sizeof(*chunk));
50 if (chunk == NULL)
51 return NULL;
53 chunk->lineno = lineno;
54 chunk->offset = offset;
56 return chunk;
57 }
59 const struct got_error *
60 got_diffoffset_alloc(struct got_diffoffset_chunks **chunks)
61 {
62 const struct got_error *err = NULL;
64 *chunks = calloc(1, sizeof(**chunks));
65 if (*chunks == NULL) {
66 err = got_error_from_errno("calloc");
67 return err;
68 }
70 SIMPLEQ_INIT(*chunks);
71 return NULL;
72 }
74 void
75 got_diffoffset_free(struct got_diffoffset_chunks *chunks)
76 {
77 struct got_diffoffset_chunk *chunk;
79 while (!SIMPLEQ_EMPTY(chunks)) {
80 chunk = SIMPLEQ_FIRST(chunks);
81 SIMPLEQ_REMOVE_HEAD(chunks, entry);
82 free(chunk);
83 }
84 free(chunks);
85 }
87 const struct got_error *
88 add_chunk(struct got_diffoffset_chunks *chunks, int lineno, int offset)
89 {
90 struct got_diffoffset_chunk *chunk;
92 chunk = alloc_chunk(lineno, offset);
93 if (chunk == NULL)
94 return got_error_from_errno("alloc_chunk");
96 SIMPLEQ_INSERT_TAIL(chunks, chunk, entry);
97 return NULL;
98 }
101 const struct got_error *
102 got_diffoffset_add(struct got_diffoffset_chunks *chunks,
103 int old_lineno, int old_length, int new_lineno, int new_length)
105 const struct got_error *err = NULL;
106 int offset;
108 if (old_length != 0) {
109 offset = new_lineno - old_lineno;
110 if (offset != 0) {
111 err = add_chunk(chunks, old_lineno, offset);
112 if (err)
113 return err;
115 } else {
116 offset = new_length;
117 if (offset != 0) {
118 err = add_chunk(chunks, old_lineno, offset);
119 if (err)
120 return err;
122 if (old_lineno == new_lineno)
123 return NULL;
126 offset = new_lineno - old_lineno + new_length - old_length;
127 if (offset != 0)
128 err = add_chunk(chunks, old_lineno + new_length, offset);
130 return err;
133 int
134 got_diffoffset_get(struct got_diffoffset_chunks *chunks, int lineno)
136 struct got_diffoffset_chunk *chunk;
137 int offset = 0;
139 SIMPLEQ_FOREACH(chunk, chunks, entry) {
140 if (chunk->lineno > lineno)
141 break;
142 offset += chunk->offset;
145 return lineno + offset;