2 * Copyright (c) 2003-2006, Maxime Henrion <mux@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 typedef long lineno_t;
45 /* Editing command and state. */
53 /* For convenience. */
54 struct keyword *keyword;
60 static int diff_geteditcmd(struct editcmd *, char *);
61 static int diff_copyln(struct editcmd *, lineno_t);
62 static void diff_write(struct editcmd *, void *, size_t);
65 diff_apply(struct stream *rd, struct stream *orig, struct stream *dest,
66 struct keyword *keyword, struct diffinfo *di)
72 int empty, error, noeol;
74 memset(&ec, 0, sizeof(ec));
81 line = stream_getln(rd, NULL);
82 while (line != NULL && strcmp(line, ".") != 0 &&
83 strcmp(line, ".+") != 0) {
85 * The server sends an empty line and then terminates
86 * with .+ for forced (and thus empty) commits.
92 line = stream_getln(rd, NULL);
95 error = diff_geteditcmd(&ec, line);
99 if (ec.cmd == EC_ADD) {
100 error = diff_copyln(&ec, ec.where);
103 for (i = 0; i < ec.count; i++) {
104 line = stream_getln(rd, &size);
107 if (line[0] == '.') {
111 diff_write(&ec, line, size);
114 assert(ec.cmd == EC_DEL);
115 error = diff_copyln(&ec, ec.where - 1);
118 for (i = 0; i < ec.count; i++) {
119 line = stream_getln(orig, NULL);
125 line = stream_getln(rd, NULL);
129 /* If we got ".+", there's no ending newline. */
130 if (strcmp(line, ".+") == 0 && !empty)
133 while ((line = stream_getln(orig, &size)) != NULL)
134 diff_write(&ec, line, size);
137 error = stream_truncate_rel(dest, -1);
139 warn("stream_truncate_rel");
146 /* Get an editing command from the diff. */
148 diff_geteditcmd(struct editcmd *ec, char *line)
154 else if (line[0] == 'd')
159 ec->where = strtol(line + 1, &end, 10);
160 if (errno || ec->where < 0 || *end != ' ')
164 ec->count = strtol(line, &end, 10);
165 if (errno || ec->count <= 0 || *end != '\0')
167 if (ec->cmd == EC_ADD) {
168 if (ec->where < ec->lasta)
170 ec->lasta = ec->where + 1;
172 if (ec->where < ec->lasta || ec->where < ec->lastd)
174 ec->lasta = ec->where;
175 ec->lastd = ec->where + ec->count;
180 /* Copy lines from the original version of the file up to line "to". */
182 diff_copyln(struct editcmd *ec, lineno_t to)
187 while (ec->editline < to) {
188 line = stream_getln(ec->orig, &size);
192 diff_write(ec, line, size);
197 /* Write a new line to the file, expanding RCS keywords appropriately. */
199 diff_write(struct editcmd *ec, void *buf, size_t size)
201 char *line, *newline;
206 ret = keyword_expand(ec->keyword, ec->di, line, size,
209 stream_write(ec->dest, newline, newsize);
212 stream_write(ec->dest, buf, size);