示例#1
0
/*
 * Apply an ed script by feeding ed itself.
 */
void
do_ed_script(void)
{
	char	*t;
	long	beginning_of_this_line;
	FILE	*pipefp = NULL;

	if (!skip_rest_of_patch) {
		if (copy_file(filearg[0], TMPOUTNAME) < 0) {
			unlink(TMPOUTNAME);
			fatal("can't create temp file %s", TMPOUTNAME);
		}
		snprintf(buf, buf_size, "%s%s%s", _PATH_ED,
		    verbose ? " " : " -s ", TMPOUTNAME);
		pipefp = popen(buf, "w");
	}
	for (;;) {
		beginning_of_this_line = ftell(pfp);
		if (pgets(true) == 0) {
			next_intuit_at(beginning_of_this_line, p_input_line);
			break;
		}
		p_input_line++;
		for (t = buf; isdigit((unsigned char)*t) || *t == ','; t++)
			;
		/* POSIX defines allowed commands as {a,c,d,i,s} */
		if (isdigit((unsigned char)*buf) && (*t == 'a' || *t == 'c' ||
		    *t == 'd' || *t == 'i' || *t == 's')) {
			if (pipefp != NULL)
				fputs(buf, pipefp);
			if (*t != 'd') {
				while (pgets(true)) {
					p_input_line++;
					if (pipefp != NULL)
						fputs(buf, pipefp);
					if (strEQ(buf, ".\n"))
						break;
				}
			}
		} else {
			next_intuit_at(beginning_of_this_line, p_input_line);
			break;
		}
	}
	if (pipefp == NULL)
		return;
	fprintf(pipefp, "w\n");
	fprintf(pipefp, "q\n");
	fflush(pipefp);
	pclose(pipefp);
	ignore_signals();
	if (!check_only) {
		if (move_file(TMPOUTNAME, outname) < 0) {
			toutkeep = true;
			chmod(TMPOUTNAME, filemode);
		} else
			chmod(outname, filemode);
	}
	set_signals(1);
}
示例#2
0
/*
 * Open the patch file at the beginning of time.
 */
void
open_patch_file(const char *filename)
{
	struct stat filestat;
	int nr, nw;

	if (filename == NULL || *filename == '\0' || strEQ(filename, "-")) {
		pfp = fopen(TMPPATNAME, "w");
		if (pfp == NULL)
			pfatal("can't create %s", TMPPATNAME);
		while ((nr = fread(buf, 1, buf_size, stdin)) > 0) {
			nw = fwrite(buf, 1, nr, pfp);
			if (nr != nw)
				pfatal("write error to %s", TMPPATNAME);
		}
		if (ferror(pfp) || fclose(pfp))
			pfatal("can't write %s", TMPPATNAME);
		filename = TMPPATNAME;
	}
	pfp = fopen(filename, "r");
	if (pfp == NULL)
		pfatal("patch file %s not found", filename);
	fstat(fileno(pfp), &filestat);
	p_filesize = filestat.st_size;
	next_intuit_at(0L, 1L);	/* start at the beginning */
	set_hunkmax();
}
示例#3
0
文件: pch.c 项目: UNGLinux/Obase
/*
 * Open the patch file at the beginning of time.
 */
void
open_patch_file(const char *filename)
{
	struct stat filestat;

	if (filename == NULL || *filename == '\0' || strEQ(filename, "-")) {
		pfp = fopen(TMPPATNAME, "w");
		if (pfp == NULL)
			pfatal("can't create %s", TMPPATNAME);
		while (fgets(buf, sizeof buf, stdin) != NULL)
			fputs(buf, pfp);
		fclose(pfp);
		filename = TMPPATNAME;
	}
	pfp = fopen(filename, "r");
	if (pfp == NULL)
		pfatal("patch file %s not found", filename);
	fstat(fileno(pfp), &filestat);
	p_filesize = filestat.st_size;
	next_intuit_at(0L, 1L);	/* start at the beginning */
	set_hunkmax();
}
示例#4
0
/*
 * True if there is more of the current diff listing to process.
 */
bool
another_hunk(void)
{
	long	line_beginning;			/* file pos of the current line */
	LINENUM	repl_beginning;			/* index of --- line */
	LINENUM	fillcnt;			/* #lines of missing ptrn or repl */
	LINENUM	fillsrc;			/* index of first line to copy */
	LINENUM	filldst;			/* index of first missing line */
	bool	ptrn_spaces_eaten;		/* ptrn was slightly misformed */
	bool	repl_could_be_missing;		/* no + or ! lines in this hunk */
	bool	repl_missing;			/* we are now backtracking */
	long	repl_backtrack_position;	/* file pos of first repl line */
	LINENUM	repl_patch_line;		/* input line number for same */
	LINENUM	ptrn_copiable;			/* # of copiable lines in ptrn */
	char	*s;
	size_t	len;
	int	context = 0;

	while (p_end >= 0) {
		if (p_end == p_efake)
			p_end = p_bfake;	/* don't free twice */
		else
			free(p_line[p_end]);
		p_end--;
	}
	p_efake = -1;

	p_max = hunkmax;	/* gets reduced when --- found */
	if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) {
		line_beginning = ftell(pfp);
		repl_beginning = 0;
		fillcnt = 0;
		fillsrc = 0;
		filldst = 0;
		ptrn_spaces_eaten = false;
		repl_could_be_missing = true;
		repl_missing = false;
		repl_backtrack_position = 0;
		repl_patch_line = 0;
		ptrn_copiable = 0;

		len = pgets(true);
		p_input_line++;
		if (len == 0 || strnNE(buf, "********", 8)) {
			next_intuit_at(line_beginning, p_input_line);
			return false;
		}
		p_context = 100;
		p_hunk_beg = p_input_line + 1;
		while (p_end < p_max) {
			line_beginning = ftell(pfp);
			len = pgets(true);
			p_input_line++;
			if (len == 0) {
				if (p_max - p_end < 4) {
					/* assume blank lines got chopped */
					strlcpy(buf, "  \n", buf_size);
				} else {
					if (repl_beginning && repl_could_be_missing) {
						repl_missing = true;
						goto hunk_done;
					}
					fatal("unexpected end of file in patch\n");
				}
			}
			p_end++;
			if (p_end >= hunkmax)
				fatal("Internal error: hunk larger than hunk "
				    "buffer size");
			p_char[p_end] = *buf;
			p_line[p_end] = NULL;
			switch (*buf) {
			case '*':
				if (strnEQ(buf, "********", 8)) {
					if (repl_beginning && repl_could_be_missing) {
						repl_missing = true;
						goto hunk_done;
					} else
						fatal("unexpected end of hunk "
						    "at line %ld\n",
						    p_input_line);
				}
				if (p_end != 0) {
					if (repl_beginning && repl_could_be_missing) {
						repl_missing = true;
						goto hunk_done;
					}
					fatal("unexpected *** at line %ld: %s",
					    p_input_line, buf);
				}
				context = 0;
				p_line[p_end] = savestr(buf);
				if (out_of_mem) {
					p_end--;
					return false;
				}
				for (s = buf; *s && !isdigit((unsigned char)*s); s++)
					;
				if (!*s)
					malformed();
				if (strnEQ(s, "0,0", 3))
					memmove(s, s + 2, strlen(s + 2) + 1);
				p_first = (LINENUM) atol(s);
				while (isdigit((unsigned char)*s))
					s++;
				if (*s == ',') {
					for (; *s && !isdigit((unsigned char)*s); s++)
						;
					if (!*s)
						malformed();
					p_ptrn_lines = ((LINENUM) atol(s)) - p_first + 1;
				} else if (p_first)
					p_ptrn_lines = 1;
				else {
					p_ptrn_lines = 0;
					p_first = 1;
				}

				/* we need this much at least */
				p_max = p_ptrn_lines + 6;
				while (p_max >= hunkmax)
					grow_hunkmax();
				p_max = hunkmax;
				break;
			case '-':
				if (buf[1] == '-') {
					if (repl_beginning ||
					    (p_end != p_ptrn_lines + 1 +
					    (p_char[p_end - 1] == '\n'))) {
						if (p_end == 1) {
							/*
							 * `old' lines were omitted;
							 * set up to fill them in
							 * from 'new' context lines.
							 */
							p_end = p_ptrn_lines + 1;
							fillsrc = p_end + 1;
							filldst = 1;
							fillcnt = p_ptrn_lines;
						} else {
							if (repl_beginning) {
								if (repl_could_be_missing) {
									repl_missing = true;
									goto hunk_done;
								}
								fatal("duplicate \"---\" at line %ld--check line numbers at line %ld\n",
								    p_input_line, p_hunk_beg + repl_beginning);
							} else {
								fatal("%s \"---\" at line %ld--check line numbers at line %ld\n",
								    (p_end <= p_ptrn_lines
								    ? "Premature"
								    : "Overdue"),
								    p_input_line, p_hunk_beg);
							}
						}
					}
					repl_beginning = p_end;
					repl_backtrack_position = ftell(pfp);
					repl_patch_line = p_input_line;
					p_line[p_end] = savestr(buf);
					if (out_of_mem) {
						p_end--;
						return false;
					}
					p_char[p_end] = '=';
					for (s = buf; *s && !isdigit((unsigned char)*s); s++)
						;
					if (!*s)
						malformed();
					p_newfirst = (LINENUM) atol(s);
					while (isdigit((unsigned char)*s))
						s++;
					if (*s == ',') {
						for (; *s && !isdigit((unsigned char)*s); s++)
							;
						if (!*s)
							malformed();
						p_repl_lines = ((LINENUM) atol(s)) -
						    p_newfirst + 1;
					} else if (p_newfirst)
						p_repl_lines = 1;
					else {
						p_repl_lines = 0;
						p_newfirst = 1;
					}
					p_max = p_repl_lines + p_end;
					if (p_max > MAXHUNKSIZE)
						fatal("hunk too large (%ld lines) at line %ld: %s",
						    p_max, p_input_line, buf);
					while (p_max >= hunkmax)
						grow_hunkmax();
					if (p_repl_lines != ptrn_copiable &&
					    (p_context != 0 || p_repl_lines != 1))
						repl_could_be_missing = false;
					break;
				}
				goto change_line;
			case '+':
			case '!':
				repl_could_be_missing = false;
		change_line:
				if (buf[1] == '\n' && canonicalize)
					strlcpy(buf + 1, " \n", buf_size - 1);
				if (!isspace((unsigned char)buf[1]) && buf[1] != '>' &&
				    buf[1] != '<' &&
				    repl_beginning && repl_could_be_missing) {
					repl_missing = true;
					goto hunk_done;
				}
				if (context >= 0) {
					if (context < p_context)
						p_context = context;
					context = -1000;
				}
				p_line[p_end] = savestr(buf + 2);
				if (out_of_mem) {
					p_end--;
					return false;
				}
				if (p_end == p_ptrn_lines) {
					if (remove_special_line()) {
						int	l;

						l = strlen(p_line[p_end]) - 1;
						(p_line[p_end])[l] = 0;
					}
				}
				break;
			case '\t':
			case '\n':	/* assume the 2 spaces got eaten */
				if (repl_beginning && repl_could_be_missing &&
				    (!ptrn_spaces_eaten ||
				    diff_type == NEW_CONTEXT_DIFF)) {
					repl_missing = true;
					goto hunk_done;
				}
				p_line[p_end] = savestr(buf);
				if (out_of_mem) {
					p_end--;
					return false;
				}
				if (p_end != p_ptrn_lines + 1) {
					ptrn_spaces_eaten |= (repl_beginning != 0);
					context++;
					if (!repl_beginning)
						ptrn_copiable++;
					p_char[p_end] = ' ';
				}
				break;
			case ' ':
				if (!isspace((unsigned char)buf[1]) &&
				    repl_beginning && repl_could_be_missing) {
					repl_missing = true;
					goto hunk_done;
				}
				context++;
				if (!repl_beginning)
					ptrn_copiable++;
				p_line[p_end] = savestr(buf + 2);
				if (out_of_mem) {
					p_end--;
					return false;
				}
				break;
			default:
				if (repl_beginning && repl_could_be_missing) {
					repl_missing = true;
					goto hunk_done;
				}
				malformed();
			}
			/* set up p_len for strncmp() so we don't have to */
			/* assume null termination */
			if (p_line[p_end])
				p_len[p_end] = strlen(p_line[p_end]);
			else
				p_len[p_end] = 0;
		}

hunk_done:
		if (p_end >= 0 && !repl_beginning)
			fatal("no --- found in patch at line %ld\n", pch_hunk_beg());

		if (repl_missing) {

			/* reset state back to just after --- */
			p_input_line = repl_patch_line;
			for (p_end--; p_end > repl_beginning; p_end--)
				free(p_line[p_end]);
			fseek(pfp, repl_backtrack_position, SEEK_SET);

			/* redundant 'new' context lines were omitted - set */
			/* up to fill them in from the old file context */
			if (!p_context && p_repl_lines == 1) {
				p_repl_lines = 0;
				p_max--;
			}
			fillsrc = 1;
			filldst = repl_beginning + 1;
			fillcnt = p_repl_lines;
			p_end = p_max;
		} else if (!p_context && fillcnt == 1) {
			/* the first hunk was a null hunk with no context */
			/* and we were expecting one line -- fix it up. */
			while (filldst < p_end) {
				p_line[filldst] = p_line[filldst + 1];
				p_char[filldst] = p_char[filldst + 1];
				p_len[filldst] = p_len[filldst + 1];
				filldst++;
			}
#if 0
			repl_beginning--;	/* this doesn't need to be fixed */
#endif
			p_end--;
			p_first++;	/* do append rather than insert */
			fillcnt = 0;
			p_ptrn_lines = 0;
		}
		if (diff_type == CONTEXT_DIFF &&
		    (fillcnt || (p_first > 1 && ptrn_copiable > 2 * p_context))) {
			if (verbose)
				say("%s\n%s\n%s\n",
				    "(Fascinating--this is really a new-style context diff but without",
				    "the telltale extra asterisks on the *** line that usually indicate",
				    "the new style...)");
			diff_type = NEW_CONTEXT_DIFF;
		}
		/* if there were omitted context lines, fill them in now */
		if (fillcnt) {
			p_bfake = filldst;	/* remember where not to free() */
			p_efake = filldst + fillcnt - 1;
			while (fillcnt-- > 0) {
				while (fillsrc <= p_end && p_char[fillsrc] != ' ')
					fillsrc++;
				if (fillsrc > p_end)
					fatal("replacement text or line numbers mangled in hunk at line %ld\n",
					    p_hunk_beg);
				p_line[filldst] = p_line[fillsrc];
				p_char[filldst] = p_char[fillsrc];
				p_len[filldst] = p_len[fillsrc];
				fillsrc++;
				filldst++;
			}
			while (fillsrc <= p_end && fillsrc != repl_beginning &&
			    p_char[fillsrc] != ' ')
				fillsrc++;
#ifdef DEBUGGING
			if (debug & 64)
				printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n",
				fillsrc, filldst, repl_beginning, p_end + 1);
#endif
			if (fillsrc != p_end + 1 && fillsrc != repl_beginning)
				malformed();
			if (filldst != p_end + 1 && filldst != repl_beginning)
				malformed();
		}
		if (p_line[p_end] != NULL) {
			if (remove_special_line()) {
				p_len[p_end] -= 1;
				(p_line[p_end])[p_len[p_end]] = 0;
			}
		}
	} else if (diff_type == UNI_DIFF) {
		LINENUM	fillold;	/* index of old lines */
		LINENUM	fillnew;	/* index of new lines */
		char	ch;

		line_beginning = ftell(pfp); /* file pos of the current line */
		len = pgets(true);
		p_input_line++;
		if (len == 0 || strnNE(buf, "@@ -", 4)) {
			next_intuit_at(line_beginning, p_input_line);
			return false;
		}
		s = buf + 4;
		if (!*s)
			malformed();
		p_first = (LINENUM) atol(s);
		while (isdigit((unsigned char)*s))
			s++;
		if (*s == ',') {
			p_ptrn_lines = (LINENUM) atol(++s);
			while (isdigit((unsigned char)*s))
				s++;
		} else
			p_ptrn_lines = 1;
		if (*s == ' ')
			s++;
		if (*s != '+' || !*++s)
			malformed();
		p_newfirst = (LINENUM) atol(s);
		while (isdigit((unsigned char)*s))
			s++;
		if (*s == ',') {
			p_repl_lines = (LINENUM) atol(++s);
			while (isdigit((unsigned char)*s))
				s++;
		} else
			p_repl_lines = 1;
		if (*s == ' ')
			s++;
		if (*s != '@')
			malformed();
		if (!p_ptrn_lines)
			p_first++;	/* do append rather than insert */
		p_max = p_ptrn_lines + p_repl_lines + 1;
		while (p_max >= hunkmax)
			grow_hunkmax();
		fillold = 1;
		fillnew = fillold + p_ptrn_lines;
		p_end = fillnew + p_repl_lines;
		snprintf(buf, buf_size, "*** %ld,%ld ****\n", p_first,
		    p_first + p_ptrn_lines - 1);
		p_line[0] = savestr(buf);
		if (out_of_mem) {
			p_end = -1;
			return false;
		}
		p_char[0] = '*';
		snprintf(buf, buf_size, "--- %ld,%ld ----\n", p_newfirst,
		    p_newfirst + p_repl_lines - 1);
		p_line[fillnew] = savestr(buf);
		if (out_of_mem) {
			p_end = 0;
			return false;
		}
		p_char[fillnew++] = '=';
		p_context = 100;
		context = 0;
		p_hunk_beg = p_input_line + 1;
		while (fillold <= p_ptrn_lines || fillnew <= p_end) {
			line_beginning = ftell(pfp);
			len = pgets(true);
			p_input_line++;
			if (len == 0) {
				if (p_max - fillnew < 3) {
					/* assume blank lines got chopped */
					strlcpy(buf, " \n", buf_size);
				} else {
					fatal("unexpected end of file in patch\n");
				}
			}
			if (*buf == '\t' || *buf == '\n') {
				ch = ' ';	/* assume the space got eaten */
				s = savestr(buf);
			} else {
				ch = *buf;
				s = savestr(buf + 1);
			}
			if (out_of_mem) {
				while (--fillnew > p_ptrn_lines)
					free(p_line[fillnew]);
				p_end = fillold - 1;
				return false;
			}
			switch (ch) {
			case '-':
				if (fillold > p_ptrn_lines) {
					free(s);
					p_end = fillnew - 1;
					malformed();
				}
				p_char[fillold] = ch;
				p_line[fillold] = s;
				p_len[fillold++] = strlen(s);
				if (fillold > p_ptrn_lines) {
					if (remove_special_line()) {
						p_len[fillold - 1] -= 1;
						s[p_len[fillold - 1]] = 0;
					}
				}
				break;
			case '=':
				ch = ' ';
				/* FALL THROUGH */
			case ' ':
				if (fillold > p_ptrn_lines) {
					free(s);
					while (--fillnew > p_ptrn_lines)
						free(p_line[fillnew]);
					p_end = fillold - 1;
					malformed();
				}
				context++;
				p_char[fillold] = ch;
				p_line[fillold] = s;
				p_len[fillold++] = strlen(s);
				s = savestr(s);
				if (out_of_mem) {
					while (--fillnew > p_ptrn_lines)
						free(p_line[fillnew]);
					p_end = fillold - 1;
					return false;
				}
				if (fillold > p_ptrn_lines) {
					if (remove_special_line()) {
						p_len[fillold - 1] -= 1;
						s[p_len[fillold - 1]] = 0;
					}
				}
				/* FALL THROUGH */
			case '+':
				if (fillnew > p_end) {
					free(s);
					while (--fillnew > p_ptrn_lines)
						free(p_line[fillnew]);
					p_end = fillold - 1;
					malformed();
				}
				p_char[fillnew] = ch;
				p_line[fillnew] = s;
				p_len[fillnew++] = strlen(s);
				if (fillold > p_ptrn_lines) {
					if (remove_special_line()) {
						p_len[fillnew - 1] -= 1;
						s[p_len[fillnew - 1]] = 0;
					}
				}
				break;
			default:
				p_end = fillnew;
				malformed();
			}
			if (ch != ' ' && context > 0) {
				if (context < p_context)
					p_context = context;
				context = -1000;
			}
		}		/* while */
	} else {		/* normal diff--fake it up */
		char	hunk_type;
		int	i;
		LINENUM	min, max;

		line_beginning = ftell(pfp);
		p_context = 0;
		len = pgets(true);
		p_input_line++;
		if (len == 0 || !isdigit((unsigned char)*buf)) {
			next_intuit_at(line_beginning, p_input_line);
			return false;
		}
		p_first = (LINENUM) atol(buf);
		for (s = buf; isdigit((unsigned char)*s); s++)
			;
		if (*s == ',') {
			p_ptrn_lines = (LINENUM) atol(++s) - p_first + 1;
			while (isdigit((unsigned char)*s))
				s++;
		} else
			p_ptrn_lines = (*s != 'a');
		hunk_type = *s;
		if (hunk_type == 'a')
			p_first++;	/* do append rather than insert */
		min = (LINENUM) atol(++s);
		for (; isdigit((unsigned char)*s); s++)
			;
		if (*s == ',')
			max = (LINENUM) atol(++s);
		else
			max = min;
		if (hunk_type == 'd')
			min++;
		p_end = p_ptrn_lines + 1 + max - min + 1;
		if (p_end > MAXHUNKSIZE)
			fatal("hunk too large (%ld lines) at line %ld: %s",
			    p_end, p_input_line, buf);
		while (p_end >= hunkmax)
			grow_hunkmax();
		p_newfirst = min;
		p_repl_lines = max - min + 1;
		snprintf(buf, buf_size, "*** %ld,%ld\n", p_first,
		    p_first + p_ptrn_lines - 1);
		p_line[0] = savestr(buf);
		if (out_of_mem) {
			p_end = -1;
			return false;
		}
		p_char[0] = '*';
		for (i = 1; i <= p_ptrn_lines; i++) {
			len = pgets(true);
			p_input_line++;
			if (len == 0)
				fatal("unexpected end of file in patch at line %ld\n",
				    p_input_line);
			if (*buf != '<')
				fatal("< expected at line %ld of patch\n",
				    p_input_line);
			p_line[i] = savestr(buf + 2);
			if (out_of_mem) {
				p_end = i - 1;
				return false;
			}
			p_len[i] = strlen(p_line[i]);
			p_char[i] = '-';
		}

		if (remove_special_line()) {
			p_len[i - 1] -= 1;
			(p_line[i - 1])[p_len[i - 1]] = 0;
		}
		if (hunk_type == 'c') {
			len = pgets(true);
			p_input_line++;
			if (len == 0)
				fatal("unexpected end of file in patch at line %ld\n",
				    p_input_line);
			if (*buf != '-')
				fatal("--- expected at line %ld of patch\n",
				    p_input_line);
		}
		snprintf(buf, buf_size, "--- %ld,%ld\n", min, max);
		p_line[i] = savestr(buf);
		if (out_of_mem) {
			p_end = i - 1;
			return false;
		}
		p_char[i] = '=';
		for (i++; i <= p_end; i++) {
			len = pgets(true);
			p_input_line++;
			if (len == 0)
				fatal("unexpected end of file in patch at line %ld\n",
				    p_input_line);
			if (*buf != '>')
				fatal("> expected at line %ld of patch\n",
				    p_input_line);
			p_line[i] = savestr(buf + 2);
			if (out_of_mem) {
				p_end = i - 1;
				return false;
			}
			p_len[i] = strlen(p_line[i]);
			p_char[i] = '+';
		}

		if (remove_special_line()) {
			p_len[i - 1] -= 1;
			(p_line[i - 1])[p_len[i - 1]] = 0;
		}
	}
	if (reverse)		/* backwards patch? */
		if (!pch_swap())
			say("Not enough memory to swap next hunk!\n");
#ifdef DEBUGGING
	if (debug & 2) {
		int	i;
		char	special;

		for (i = 0; i <= p_end; i++) {
			if (i == p_ptrn_lines)
				special = '^';
			else
				special = ' ';
			fprintf(stderr, "%3d %c %c %s", i, p_char[i],
			    special, p_line[i]);
			fflush(stderr);
		}
	}
#endif
	if (p_end + 1 < hunkmax)/* paranoia reigns supreme... */
		p_char[p_end + 1] = '^';	/* add a stopper for apply_hunk */
	return true;
}