📄 pch.c
字号:
p_strip_trailing_cr = strip_trailing_cr; retval = NORMAL_DIFF; goto scan_exit; } } scan_exit: /* To intuit `inname', the name of the file to patch, use the algorithm specified by POSIX 1003.1-2001 XCU lines 25680-26599 (with some modifications if posixly_correct is zero): - Take the old and new names from the context header if present, and take the index name from the `Index:' line if present and if either the old and new names are both absent or posixly_correct is nonzero. Consider the file names to be in the order (old, new, index). - If some named files exist, use the first one if posixly_correct is nonzero, the best one otherwise. - If patch_get is nonzero, and no named files exist, but an RCS or SCCS master file exists, use the first named file with an RCS or SCCS master. - If no named files exist, no RCS or SCCS master was found, some names are given, posixly_correct is zero, and the patch appears to create a file, then use the best name requiring the creation of the fewest directories. - Otherwise, report failure by setting `inname' to 0; this causes our invoker to ask the user for a file name. */ i = NONE; if (!inname) { enum nametype i0 = NONE; if (! posixly_correct && (name[OLD] || name[NEW]) && name[INDEX]) { free (name[INDEX]); name[INDEX] = 0; } for (i = OLD; i <= INDEX; i++) if (name[i]) { if (i0 != NONE && strcmp (name[i0], name[i]) == 0) { /* It's the same name as before; reuse stat results. */ stat_errno[i] = stat_errno[i0]; if (! stat_errno[i]) st[i] = st[i0]; } else if (stat (name[i], &st[i]) != 0) stat_errno[i] = errno; else { stat_errno[i] = 0; if (posixly_correct) break; } i0 = i; } if (! posixly_correct) { bool is_empty; i = best_name (name, stat_errno); if (i == NONE && patch_get) { enum nametype nope = NONE; for (i = OLD; i <= INDEX; i++) if (name[i]) { char const *cs; char *getbuf; char *diffbuf; bool readonly = (outfile && strcmp (outfile, name[i]) != 0); if (nope == NONE || strcmp (name[nope], name[i]) != 0) { cs = (version_controller (name[i], readonly, (struct stat *) 0, &getbuf, &diffbuf)); version_controlled[i] = !! cs; if (cs) { if (version_get (name[i], cs, false, readonly, getbuf, &st[i])) stat_errno[i] = 0; else version_controlled[i] = 0; free (getbuf); if (diffbuf) free (diffbuf); if (! stat_errno[i]) break; } } nope = i; } } is_empty = i == NONE || st[i].st_size == 0; if ((! is_empty) < p_says_nonexistent[reverse ^ is_empty]) { assert (i0 != NONE); reverse ^= ok_to_reverse ("The next patch%s would %s the file %s,\nwhich %s!", reverse ? ", when reversed," : "", (i == NONE ? "delete" : st[i].st_size == 0 ? "empty out" : "create"), quotearg (name[i == NONE || st[i].st_size == 0 ? i0 : i]), (i == NONE ? "does not exist" : st[i].st_size == 0 ? "is already empty" : "already exists")); } if (i == NONE && p_says_nonexistent[reverse]) { int newdirs[3]; int newdirs_min = INT_MAX; int distance_from_minimum[3]; for (i = OLD; i <= INDEX; i++) if (name[i]) { newdirs[i] = (prefix_components (name[i], false) - prefix_components (name[i], true)); if (newdirs[i] < newdirs_min) newdirs_min = newdirs[i]; } for (i = OLD; i <= INDEX; i++) if (name[i]) distance_from_minimum[i] = newdirs[i] - newdirs_min; i = best_name (name, distance_from_minimum); } } } if (i == NONE) inerrno = -1; else { inname = name[i]; name[i] = 0; inerrno = stat_errno[i]; invc = version_controlled[i]; instat = st[i]; } for (i = OLD; i <= INDEX; i++) if (name[i]) free (name[i]); return retval;}/* Count the path name components in FILENAME's prefix. If CHECKDIRS is true, count only existing directories. */static intprefix_components (char *filename, bool checkdirs){ int count = 0; struct stat stat_buf; int stat_result; char *f = filename + FILESYSTEM_PREFIX_LEN (filename); if (*f) while (*++f) if (ISSLASH (f[0]) && ! ISSLASH (f[-1])) { if (checkdirs) { *f = '\0'; stat_result = stat (filename, &stat_buf); *f = '/'; if (! (stat_result == 0 && S_ISDIR (stat_buf.st_mode))) break; } count++; } return count;}/* Return the index of the best of NAME[OLD], NAME[NEW], and NAME[INDEX]. Ignore null names, and ignore NAME[i] if IGNORE[i] is nonzero. Return NONE if all names are ignored. */static enum nametypebest_name (char *const *name, int const *ignore){ enum nametype i; int components[3]; int components_min = INT_MAX; size_t basename_len[3]; size_t basename_len_min = SIZE_MAX; size_t len[3]; size_t len_min = SIZE_MAX; for (i = OLD; i <= INDEX; i++) if (name[i] && !ignore[i]) { /* Take the names with the fewest prefix components. */ components[i] = prefix_components (name[i], false); if (components_min < components[i]) continue; components_min = components[i]; /* Of those, take the names with the shortest basename. */ basename_len[i] = strlen (base_name (name[i])); if (basename_len_min < basename_len[i]) continue; basename_len_min = basename_len[i]; /* Of those, take the shortest names. */ len[i] = strlen (name[i]); if (len_min < len[i]) continue; len_min = len[i]; } /* Of those, take the first name. */ for (i = OLD; i <= INDEX; i++) if (name[i] && !ignore[i] && components[i] == components_min && basename_len[i] == basename_len_min && len[i] == len_min) break; return i;}/* Remember where this patch ends so we know where to start up again. */static voidnext_intuit_at (file_offset file_pos, LINENUM file_line){ p_base = file_pos; p_bline = file_line;}/* Basically a verbose fseek() to the actual diff listing. */static voidskip_to (file_offset file_pos, LINENUM file_line){ register FILE *i = pfp; register FILE *o = stdout; register int c; assert(p_base <= file_pos); if ((verbosity == VERBOSE || !inname) && p_base < file_pos) { Fseek (i, p_base, SEEK_SET); say ("The text leading up to this was:\n--------------------------\n"); while (file_tell (i) < file_pos) { putc ('|', o); do { if ((c = getc (i)) == EOF) read_fatal (); putc (c, o); } while (c != '\n'); } say ("--------------------------\n"); } else Fseek (i, file_pos, SEEK_SET); p_input_line = file_line - 1;}/* Make this a function for better debugging. */static voidmalformed (void){ char numbuf[LINENUM_LENGTH_BOUND + 1]; fatal ("malformed patch at line %s: %s", format_linenum (numbuf, p_input_line), buf); /* about as informative as "Syntax error" in C */}/* Parse a line number from a string. Return the address of the first char after the number. */static char *scan_linenum (char *s0, LINENUM *linenum){ char *s; LINENUM n = 0; bool overflow = false; char numbuf[LINENUM_LENGTH_BOUND + 1]; for (s = s0; ISDIGIT (*s); s++) { LINENUM new_n = 10 * n + (*s - '0'); overflow |= new_n / 10 != n; n = new_n; } if (s == s0) fatal ("missing line number at line %s: %s", format_linenum (numbuf, p_input_line), buf); if (overflow) fatal ("line number %.*s is too large at line %s: %s", (int) (s - s0), s0, format_linenum (numbuf, p_input_line), buf); *linenum = n; return s;}/* 1 if there is more of the current diff listing to process; 0 if not; -1 if ran out of memory. */intanother_hunk (enum diff difftype, bool rev){ register char *s; register LINENUM context = 0; register size_t chars_read; char numbuf0[LINENUM_LENGTH_BOUND + 1]; char numbuf1[LINENUM_LENGTH_BOUND + 1]; char numbuf2[LINENUM_LENGTH_BOUND + 1]; char numbuf3[LINENUM_LENGTH_BOUND + 1]; 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 (difftype == CONTEXT_DIFF || difftype == NEW_CONTEXT_DIFF) { file_offset line_beginning = file_tell (pfp); /* file pos of the current line */ LINENUM repl_beginning = 0; /* index of --- line */ register LINENUM fillcnt = 0; /* #lines of missing ptrn or repl */ register LINENUM fillsrc; /* index of first line to copy */ register LINENUM filldst; /* index of first missing line */ bool ptrn_spaces_eaten = false; /* ptrn was slightly misformed */ bool some_context = false; /* (perhaps internal) context seen */ register bool repl_could_be_missing = true; bool ptrn_missing = false; /* The pattern was missing. */ bool repl_missing = false; /* Likewise for replacement. */ file_offset repl_backtrack_position = 0; /* file pos of first repl line */ LINENUM repl_patch_line; /* input line number for same */ LINENUM repl_context; /* context for same */ LINENUM ptrn_prefix_context = -1; /* lines in pattern prefix context */ LINENUM ptrn_suffix_context = -1; /* lines in pattern suffix context */ LINENUM repl_prefix_context = -1; /* lines in replac. prefix context */ LINENUM ptrn_copiable = 0; /* # of copiable lines in ptrn */ LINENUM repl_copiable = 0; /* Likewise for replacement. */ /* Pacify `gcc -Wall'. */ fillsrc = filldst = repl_patch_line = repl_context = 0; chars_read = get_line (); if (chars_read == (size_t) -1 || chars_read <= 8 || strncmp (buf, "********", 8) != 0) { next_intuit_at(line_beginning,p_input_line); return chars_read == (size_t) -1 ? -1 : 0; } p_hunk_beg = p_input_line + 1; while (p_end < p_max) { chars_read = get_line (); if (chars_read == (size_t) -1) return -1; if (!chars_read) { if (repl_beginning && repl_could_be_missing) { repl_missing = true; goto hunk_done; } if (p_max - p_end < 4) { strcpy (buf, " \n"); /* assume blank lines got chopped */ chars_read = 3; } else { fatal ("unexpected end of file in patch"); } } p_end++; if (p_end == hunkmax) fatal ("unterminated hunk starting at line %s; giving up at line %s: %s", format_linenum (numbuf0, pch_hunk_beg ()), format_linenum (numbuf1, p_input_line), buf); assert(p_end < hunkmax); p_Char[p_end] = *buf; p_len[p_end] = 0; p_line[p_end] = 0; 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 %s", format_linenum (numbuf0, p_input_line)); } if (p_end != 0) { if (repl_beginning && repl_could_be_missing) { repl_missing = true; goto hunk_done; } fatal ("unexpected `***' at line %s: %s", format_linenum (numbuf0, p_input_line), buf); } context = 0; p_len[p_end] = strlen (buf); if (! (p_line[p_end] = savestr (buf))) { p_end--; return -1; } for (s = buf; *s && !ISDIGIT (*s); s++) continue; if (strnEQ(s,"0,0",3)) remove_prefix (s, 2); s = scan_linenum (s, &p_first); if (*s == ',') { while (*s && !ISDIGIT (*s)) s++; scan_linenum (s, &p_ptrn_lines); p_ptrn_lines += 1 - p_first; } else if (p_first) p_ptrn_lines = 1; else { p_ptrn_lines = 0; p_first = 1; } p_max = p_ptrn_lines + 6; /* we need this much at least */ while (p_max >= hunkmax) if (! grow_hunkmax ()) return -1; p_max = hunkmax; break; case '-': if (buf[1] != '-') goto change_line; if (ptrn_prefix_context == -1) ptrn_prefix_context = context; ptrn_suffix_context = context; 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. */ ptrn_missing = true; p_end = p_ptrn_lines + 1; ptrn_prefix_context = ptrn_suffix_context = -1; fillsrc = p_end + 1; filldst = 1; fillcnt = p_ptrn_lines; } else if (! repl_beginning) fatal ("%s `---' at line %s; check line numbers at line %s", (p_end <= p_ptrn_lines ? "Premature" : "Overdue"), format_linenum (numbuf0, p_input_line), format_linenum (numbuf1, p_hunk_beg)); else if (! repl_could_be_missing) fatal ("duplicate `---' at line %s; check line numbers at line %s", format_linenum (numbuf0, p_input_line), format_linenum (numbuf1, p_hunk_beg + repl_beginning)); else { repl_missing = true; goto hunk_done; } } repl_beginning = p_end; repl_backtrack_position = file_tell (pfp); repl_patch_line = p_input_line; repl_context = context; p_len[p_end] = strlen (buf); if (! (p_line[p_end] = savestr (buf))) { p_end--;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -