assert(fillsrc == p_end + 1 || fillsrc == repl_beginning); assert(filldst == p_end + 1 || filldst == repl_beginning);
if (fillsrc != p_end + 1 && fillsrc != repl_beginning) malformed(); if (filldst != p_end + 1 && filldst != repl_beginning) malformed();
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, *ret;	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--;	}	assert(p_end == -1);	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;		ptrn_spaces_eaten = FALSE;		repl_could_be_missing = TRUE;		repl_missing = FALSE;		repl_backtrack_position = 0;		ptrn_copiable = 0;		ret = pgets(buf, sizeof buf, pfp);		p_input_line++;		if (ret == NULL || 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);			ret = pgets(buf, sizeof buf, pfp);			p_input_line++;			if (ret == NULL) {				if (p_max - p_end < 4) {					/* assume blank lines got chopped */					strlcpy(buf, "  \n", sizeof buf);				} else {					if (repl_beginning && repl_could_be_missing) {						repl_missing = TRUE;						goto hunk_done;					}					fatal("unexpected end of file in patch\n");				}			}			p_end++;			assert(p_end < hunkmax);			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(*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(*s))					s++;				if (*s == ',') {					for (; *s && !isdigit(*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(*s); s++)						;					if (!*s)						malformed();					p_newfirst = (LINENUM) atol(s);					while (isdigit(*s))						s++;					if (*s == ',') {						for (; *s && !isdigit(*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", sizeof buf - 1);				if (!isspace(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	len;						len = strlen(p_line[p_end]) - 1;						(p_line[p_end])[len] = 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(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			assert(fillsrc == p_end + 1 || fillsrc == repl_beginning);			assert(filldst == p_end + 1 || filldst == repl_beginning);		}		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) {		long	line_beginning = ftell(pfp); /* file pos of the current line */		LINENUM	fillsrc;	/* index of old lines */		LINENUM	filldst;	/* index of new lines */		char	ch;		ret = pgets(buf, sizeof buf, pfp);		p_input_line++;		if (ret == NULL || 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(*s))			s++;		if (*s == ',') {			p_ptrn_lines = (LINENUM) atol(++s);			while (isdigit(*s))				s++;		} else			p_ptrn_lines = 1;		if (*s == ' ')			s++;		if (*s != '+' || !*++s)			malformed();		p_newfirst = (LINENUM) atol(s);		while (isdigit(*s))			s++;		if (*s == ',') {			p_repl_lines = (LINENUM) atol(++s);			while (isdigit(*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();		fillsrc = 1;		filldst = fillsrc + p_ptrn_lines;		p_end = filldst + p_repl_lines;		snprintf(buf, sizeof buf, "*** %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, sizeof buf, "--- %ld,%ld ----\n", p_newfirst,		    p_newfirst + p_repl_lines - 1);		p_line[filldst] = savestr(buf);		if (out_of_mem) {			p_end = 0;			return FALSE;		}		p_char[filldst++] = '=';		p_context = 100;		context = 0;		p_hunk_beg = p_input_line + 1;		while (fillsrc <= p_ptrn_lines || filldst <= p_end) {			line_beginning = ftell(pfp);			ret = pgets(buf, sizeof buf, pfp);			p_input_line++;			if (ret == NULL) {				if (p_max - filldst < 3) {					/* assume blank lines got chopped */					strlcpy(buf, " \n", sizeof buf);				} 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 (--filldst > p_ptrn_lines)					free(p_line[filldst]);				p_end = fillsrc - 1;				return FALSE;			}			switch (ch) {			case '-':				if (fillsrc > p_ptrn_lines) {					free(s);					p_end = filldst - 1;					malformed();				}				p_char[fillsrc] = ch;				p_line[fillsrc] = s;				p_len[fillsrc++] = strlen(s);				if (fillsrc > p_ptrn_lines) {					if (remove_special_line()) {						p_len[fillsrc - 1] -= 1;						s[p_len[fillsrc - 1]] = 0;					}				}				break;			case '=':				ch = ' ';				/* FALL THROUGH */			case ' ':				if (fillsrc > p_ptrn_lines) {					free(s);					while (--filldst > p_ptrn_lines)						free(p_line[filldst]);					p_end = fillsrc - 1;					malformed();				}				context++;				p_char[fillsrc] = ch;				p_line[fillsrc] = s;				p_len[fillsrc++] = strlen(s);				s = savestr(s);				if (out_of_mem) {					while (--filldst > p_ptrn_lines)						free(p_line[filldst]);					p_end = fillsrc - 1;					return FALSE;				}				/* FALL THROUGH */			case '+':				if (filldst > p_end) {					free(s);					while (--filldst > p_ptrn_lines)						free(p_line[filldst]);					p_end = fillsrc - 1;					malformed();				}				p_char[filldst] = ch;				p_line[filldst] = s;				p_len[filldst++] = strlen(s);				if (fillsrc > p_ptrn_lines) {					if (remove_special_line()) {						p_len[filldst - 1] -= 1;						s[p_len[filldst - 1]] = 0;					}				}				break;			default:				p_end = filldst;				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;		long	line_beginning = ftell(pfp);		p_context = 0;		ret = pgets(buf, sizeof buf, pfp);		p_input_line++;		if (ret == NULL || !isdigit(*buf)) {			next_intuit_at(line_beginning, p_input_line);			return FALSE;		}		p_first = (LINENUM) atol(buf);		for (s = buf; isdigit(*s); s++)			;		if (*s == ',') {			p_ptrn_lines = (LINENUM) atol(++s) - p_first + 1;			while (isdigit(*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(*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, sizeof buf, "*** %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++) {			ret = pgets(buf, sizeof buf, pfp);			p_input_line++;			if (ret == NULL)				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') {			ret = pgets(buf, sizeof buf, pfp);			p_input_line++;			if (ret == NULL)				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, sizeof(buf), "--- %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++) {			ret = pgets(buf, sizeof buf, pfp);			p_input_line++;			if (ret == NULL)				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;}