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;
63 struct got_diffoffset_chunk *first;
65 first = alloc_chunk(0, 0);
66 if (first == NULL)
67 return got_error_from_errno();
69 *chunks = calloc(1, sizeof(**chunks));
70 if (*chunks == NULL) {
71 err = got_error_from_errno();
72 free(first);
73 return err;
74 }
76 SIMPLEQ_INIT(*chunks);
77 SIMPLEQ_INSERT_HEAD(*chunks, first, entry);
79 return NULL;
80 }
82 void
83 got_diffoffset_free(struct got_diffoffset_chunks *chunks)
84 {
85 struct got_diffoffset_chunk *chunk;
87 while (!SIMPLEQ_EMPTY(chunks)) {
88 chunk = SIMPLEQ_FIRST(chunks);
89 SIMPLEQ_REMOVE_HEAD(chunks, entry);
90 free(chunk);
91 }
92 free(chunks);
93 }
95 const struct got_error *
96 got_diffoffset_add(struct got_diffoffset_chunks *chunks,
97 int old_lineno, int old_length, int new_lineno, int new_length)
98 {
99 struct got_diffoffset_chunk *chunk1, *chunk2;
101 chunk1 = alloc_chunk(old_lineno, new_lineno - old_lineno);
102 if (chunk1 == NULL)
103 return got_error_from_errno();
105 chunk2 = alloc_chunk(old_lineno + old_length,
106 new_lineno - old_lineno + new_length - old_length);
107 if (chunk2 == NULL) {
108 const struct got_error *err = got_error_from_errno();
109 free(chunk1);
110 return err;
113 SIMPLEQ_INSERT_TAIL(chunks, chunk1, entry);
114 SIMPLEQ_INSERT_TAIL(chunks, chunk2, entry);
115 return NULL;
118 int
119 got_diffoffset_get(struct got_diffoffset_chunks *chunks, int lineno)
121 struct got_diffoffset_chunk *chunk, *prev;
123 prev = SIMPLEQ_FIRST(chunks);
124 SIMPLEQ_FOREACH(chunk, chunks, entry) {
125 if (chunk->lineno > lineno)
126 break;
127 prev = chunk;
130 return lineno + prev->offset;