original netbsd patch
This commit is contained in:
		
							parent
							
								
									6657c0e58e
								
							
						
					
					
						commit
						f50f1bf7d6
					
				
							
								
								
									
										8
									
								
								commands/patch/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								commands/patch/Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					#	$NetBSD: Makefile,v 1.9 2008/09/19 18:33:34 joerg Exp $
 | 
				
			||||||
 | 
					#	$OpenBSD: Makefile,v 1.4 2005/05/16 15:22:46 espie Exp $
 | 
				
			||||||
 | 
					#	$DragonFly: src/usr.bin/patch/Makefile,v 1.8 2008/08/10 23:50:12 joerg Exp $
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PROG=	patch
 | 
				
			||||||
 | 
					SRCS=	patch.c pch.c inp.c util.c backupfile.c mkpath.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.include <bsd.prog.mk>
 | 
				
			||||||
							
								
								
									
										254
									
								
								commands/patch/backupfile.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										254
									
								
								commands/patch/backupfile.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,254 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * $OpenBSD: backupfile.c,v 1.19 2006/03/11 19:41:30 otto Exp $
 | 
				
			||||||
 | 
					 * $DragonFly: src/usr.bin/patch/backupfile.c,v 1.5 2008/08/11 00:05:06 joerg Exp $
 | 
				
			||||||
 | 
					 * $NetBSD: backupfile.c,v 1.14 2008/09/19 18:33:34 joerg Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * backupfile.c -- make Emacs style backup file names
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 1990 Free Software Foundation, Inc.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify it
 | 
				
			||||||
 | 
					 * without restriction.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful, but WITHOUT
 | 
				
			||||||
 | 
					 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * David MacKenzie <djm@ai.mit.edu>. Some algorithms adapted from GNU Emacs.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sys/cdefs.h>
 | 
				
			||||||
 | 
					__RCSID("$NetBSD: backupfile.c,v 1.14 2008/09/19 18:33:34 joerg Exp $");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					#include <dirent.h>
 | 
				
			||||||
 | 
					#include <libgen.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "backupfile.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Which type of backup file names are generated. */
 | 
				
			||||||
 | 
					enum backup_type backup_type = none;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * The extension added to file names to produce a simple (as opposed to
 | 
				
			||||||
 | 
					 * numbered) backup file name.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const char	*simple_backup_suffix = "~";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char	*concat(const char *, const char *);
 | 
				
			||||||
 | 
					static char	*make_version_name(const char *, int);
 | 
				
			||||||
 | 
					static int	max_backup_version(const char *, const char *);
 | 
				
			||||||
 | 
					static int	version_number(const char *, const char *, size_t);
 | 
				
			||||||
 | 
					static int	argmatch(const char *, const char **);
 | 
				
			||||||
 | 
					static void	invalid_arg(const char *, const char *, int);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Return the name of the new backup file for file FILE, allocated with
 | 
				
			||||||
 | 
					 * malloc.  Return 0 if out of memory. FILE must not end with a '/' unless it
 | 
				
			||||||
 | 
					 * is the root directory. Do not call this function if backup_type == none.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					char *
 | 
				
			||||||
 | 
					find_backup_file_name(const char *file)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char	*dir, *base_versions, *tmp_file;
 | 
				
			||||||
 | 
						int	highest_backup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (backup_type == simple)
 | 
				
			||||||
 | 
							return concat(file, simple_backup_suffix);
 | 
				
			||||||
 | 
						tmp_file = strdup(file);
 | 
				
			||||||
 | 
						if (tmp_file == NULL)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						base_versions = concat(basename(tmp_file), ".~");
 | 
				
			||||||
 | 
						free(tmp_file);
 | 
				
			||||||
 | 
						if (base_versions == NULL)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						tmp_file = strdup(file);
 | 
				
			||||||
 | 
						if (tmp_file == NULL) {
 | 
				
			||||||
 | 
							free(base_versions);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						dir = dirname(tmp_file);
 | 
				
			||||||
 | 
						if (dir == NULL) {
 | 
				
			||||||
 | 
							free(base_versions);
 | 
				
			||||||
 | 
							free(tmp_file);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						highest_backup = max_backup_version(base_versions, dir);
 | 
				
			||||||
 | 
						free(base_versions);
 | 
				
			||||||
 | 
						free(tmp_file);
 | 
				
			||||||
 | 
						if (backup_type == numbered_existing && highest_backup == 0)
 | 
				
			||||||
 | 
							return concat(file, simple_backup_suffix);
 | 
				
			||||||
 | 
						return make_version_name(file, highest_backup + 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Return the number of the highest-numbered backup file for file FILE in
 | 
				
			||||||
 | 
					 * directory DIR.  If there are no numbered backups of FILE in DIR, or an
 | 
				
			||||||
 | 
					 * error occurs reading DIR, return 0. FILE should already have ".~" appended
 | 
				
			||||||
 | 
					 * to it.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					max_backup_version(const char *file, const char *dir)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						DIR	*dirp;
 | 
				
			||||||
 | 
						struct dirent	*dp;
 | 
				
			||||||
 | 
						int	highest_version, this_version;
 | 
				
			||||||
 | 
						size_t	file_name_length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dirp = opendir(dir);
 | 
				
			||||||
 | 
						if (dirp == NULL)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						highest_version = 0;
 | 
				
			||||||
 | 
						file_name_length = strlen(file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while ((dp = readdir(dirp)) != NULL) {
 | 
				
			||||||
 | 
							if (dp->d_namlen <= file_name_length)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this_version = version_number(file, dp->d_name, file_name_length);
 | 
				
			||||||
 | 
							if (this_version > highest_version)
 | 
				
			||||||
 | 
								highest_version = this_version;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						closedir(dirp);
 | 
				
			||||||
 | 
						return highest_version;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Return a string, allocated with malloc, containing "FILE.~VERSION~".
 | 
				
			||||||
 | 
					 * Return 0 if out of memory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static char *
 | 
				
			||||||
 | 
					make_version_name(const char *file, int version)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char	*backup_name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (asprintf(&backup_name, "%s.~%d~", file, version) == -1)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						return backup_name;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * If BACKUP is a numbered backup of BASE, return its version number;
 | 
				
			||||||
 | 
					 * otherwise return 0.  BASE_LENGTH is the length of BASE. BASE should
 | 
				
			||||||
 | 
					 * already have ".~" appended to it.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					version_number(const char *base, const char *backup, size_t base_length)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int		version;
 | 
				
			||||||
 | 
						const char	*p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						version = 0;
 | 
				
			||||||
 | 
						if (!strncmp(base, backup, base_length) && ISDIGIT(backup[base_length])) {
 | 
				
			||||||
 | 
							for (p = &backup[base_length]; ISDIGIT(*p); ++p)
 | 
				
			||||||
 | 
								version = version * 10 + *p - '0';
 | 
				
			||||||
 | 
							if (p[0] != '~' || p[1])
 | 
				
			||||||
 | 
								version = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return version;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Return the newly-allocated concatenation of STR1 and STR2. If out of
 | 
				
			||||||
 | 
					 * memory, return 0.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static char  *
 | 
				
			||||||
 | 
					concat(const char *str1, const char *str2)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char	*newstr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (asprintf(&newstr, "%s%s", str1, str2) == -1)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						return newstr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * If ARG is an unambiguous match for an element of the null-terminated array
 | 
				
			||||||
 | 
					 * OPTLIST, return the index in OPTLIST of the matched element, else -1 if it
 | 
				
			||||||
 | 
					 * does not match any element or -2 if it is ambiguous (is a prefix of more
 | 
				
			||||||
 | 
					 * than one element).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					argmatch(const char *arg, const char **optlist)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int	i;	/* Temporary index in OPTLIST. */
 | 
				
			||||||
 | 
						size_t	arglen;	/* Length of ARG. */
 | 
				
			||||||
 | 
						int	matchind = -1;	/* Index of first nonexact match. */
 | 
				
			||||||
 | 
						int	ambiguous = 0;	/* If nonzero, multiple nonexact match(es). */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						arglen = strlen(arg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Test all elements for either exact match or abbreviated matches.  */
 | 
				
			||||||
 | 
						for (i = 0; optlist[i]; i++) {
 | 
				
			||||||
 | 
							if (!strncmp(optlist[i], arg, arglen)) {
 | 
				
			||||||
 | 
								if (strlen(optlist[i]) == arglen)
 | 
				
			||||||
 | 
									/* Exact match found.  */
 | 
				
			||||||
 | 
									return i;
 | 
				
			||||||
 | 
								else if (matchind == -1)
 | 
				
			||||||
 | 
									/* First nonexact match found.  */
 | 
				
			||||||
 | 
									matchind = i;
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									/* Second nonexact match found.  */
 | 
				
			||||||
 | 
									ambiguous = 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ambiguous)
 | 
				
			||||||
 | 
							return -2;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return matchind;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Error reporting for argmatch. KIND is a description of the type of entity
 | 
				
			||||||
 | 
					 * that was being matched. VALUE is the invalid value that was given. PROBLEM
 | 
				
			||||||
 | 
					 * is the return value from argmatch.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					invalid_arg(const char *kind, const char *value, int problem)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						fprintf(stderr, "patch: ");
 | 
				
			||||||
 | 
						if (problem == -1)
 | 
				
			||||||
 | 
							fprintf(stderr, "invalid");
 | 
				
			||||||
 | 
						else			/* Assume -2. */
 | 
				
			||||||
 | 
							fprintf(stderr, "ambiguous");
 | 
				
			||||||
 | 
						fprintf(stderr, " %s `%s'\n", kind, value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *backup_args[] = {
 | 
				
			||||||
 | 
						"never", "simple", "nil", "existing", "t", "numbered", 0
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static enum backup_type backup_types[] = {
 | 
				
			||||||
 | 
						simple, simple, numbered_existing,
 | 
				
			||||||
 | 
						numbered_existing, numbered, numbered
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Return the type of backup indicated by VERSION. Unique abbreviations are
 | 
				
			||||||
 | 
					 * accepted.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					enum backup_type
 | 
				
			||||||
 | 
					get_version(const char *version)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int	i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (version == NULL || *version == '\0')
 | 
				
			||||||
 | 
							return numbered_existing;
 | 
				
			||||||
 | 
						i = argmatch(version, backup_args);
 | 
				
			||||||
 | 
						if (i >= 0)
 | 
				
			||||||
 | 
							return backup_types[i];
 | 
				
			||||||
 | 
						invalid_arg("version control type", version, i);
 | 
				
			||||||
 | 
						exit(2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										42
									
								
								commands/patch/backupfile.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								commands/patch/backupfile.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * $OpenBSD: backupfile.h,v 1.6 2003/07/28 18:35:36 otto Exp $
 | 
				
			||||||
 | 
					 * $DragonFly: src/usr.bin/patch/backupfile.h,v 1.3 2007/09/29 23:11:10 swildner Exp $
 | 
				
			||||||
 | 
					 * $NetBSD: backupfile.h,v 1.6 2008/09/19 18:33:34 joerg Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * backupfile.h -- declarations for making Emacs style backup file names
 | 
				
			||||||
 | 
					 * Copyright (C) 1990 Free Software Foundation, Inc.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify it
 | 
				
			||||||
 | 
					 * without restriction.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful, but WITHOUT
 | 
				
			||||||
 | 
					 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* When to make backup files. */
 | 
				
			||||||
 | 
					enum backup_type {
 | 
				
			||||||
 | 
						/* Never make backups. */
 | 
				
			||||||
 | 
						none,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Make simple backups of every file. */
 | 
				
			||||||
 | 
						simple,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Make numbered backups of files that already have numbered backups,
 | 
				
			||||||
 | 
						 * and simple backups of the others.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						numbered_existing,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Make numbered backups of every file. */
 | 
				
			||||||
 | 
						numbered
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern enum backup_type backup_type;
 | 
				
			||||||
 | 
					extern const char	*simple_backup_suffix;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char		*find_backup_file_name(const char *file);
 | 
				
			||||||
 | 
					enum backup_type get_version(const char *version);
 | 
				
			||||||
							
								
								
									
										122
									
								
								commands/patch/common.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								commands/patch/common.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,122 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * $OpenBSD: common.h,v 1.26 2006/03/11 19:41:30 otto Exp $
 | 
				
			||||||
 | 
					 * $DragonFly: src/usr.bin/patch/common.h,v 1.5 2008/08/10 23:50:12 joerg Exp $
 | 
				
			||||||
 | 
					 * $NetBSD: common.h,v 1.19 2008/09/19 18:33:34 joerg Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * patch - a program to apply diffs to original files
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Copyright 1986, Larry Wall
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					 * modification, are permitted provided that the following condition is met:
 | 
				
			||||||
 | 
					 * 1. Redistributions of source code must retain the above copyright notice,
 | 
				
			||||||
 | 
					 * this condition and the following disclaimer.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
 | 
				
			||||||
 | 
					 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
				
			||||||
 | 
					 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
				
			||||||
 | 
					 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
				
			||||||
 | 
					 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
				
			||||||
 | 
					 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
				
			||||||
 | 
					 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
				
			||||||
 | 
					 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
				
			||||||
 | 
					 * SUCH DAMAGE.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * -C option added in 1998, original code by Marc Espie, based on FreeBSD
 | 
				
			||||||
 | 
					 * behaviour
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DEBUGGING
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* constants */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAXHUNKSIZE 100000	/* is this enough lines? */
 | 
				
			||||||
 | 
					#define INITHUNKMAX 125		/* initial dynamic allocation size */
 | 
				
			||||||
 | 
					#define MAXLINELEN 8192
 | 
				
			||||||
 | 
					#define BUFFERSIZE 1024
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SCCSPREFIX "s."
 | 
				
			||||||
 | 
					#define GET "get -e %s"
 | 
				
			||||||
 | 
					#define SCCSDIFF "get -p %s | diff - %s >/dev/null"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RCSSUFFIX ",v"
 | 
				
			||||||
 | 
					#define CHECKOUT "co -l %s"
 | 
				
			||||||
 | 
					#define RCSDIFF "rcsdiff %s > /dev/null"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ORIGEXT ".orig"
 | 
				
			||||||
 | 
					#define REJEXT ".rej"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* handy definitions */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define strNE(s1,s2) (strcmp(s1, s2))
 | 
				
			||||||
 | 
					#define strEQ(s1,s2) (!strcmp(s1, s2))
 | 
				
			||||||
 | 
					#define strnNE(s1,s2,l) (strncmp(s1, s2, l))
 | 
				
			||||||
 | 
					#define strnEQ(s1,s2,l) (!strncmp(s1, s2, l))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* typedefs */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef long    LINENUM;	/* must be signed */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* globals */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern mode_t	filemode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern char	buf[MAXLINELEN];/* general purpose buffer */
 | 
				
			||||||
 | 
					extern size_t	buf_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern bool	using_plan_a;	/* try to keep everything in memory */
 | 
				
			||||||
 | 
					extern bool	out_of_mem;	/* ran out of memory in plan a */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAXFILEC 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern char	*filearg[MAXFILEC];
 | 
				
			||||||
 | 
					extern bool	ok_to_create_file;
 | 
				
			||||||
 | 
					extern char	*outname;
 | 
				
			||||||
 | 
					extern char	*origprae;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern char	*TMPOUTNAME;
 | 
				
			||||||
 | 
					extern char	*TMPINNAME;
 | 
				
			||||||
 | 
					extern char	*TMPREJNAME;
 | 
				
			||||||
 | 
					extern char	*TMPPATNAME;
 | 
				
			||||||
 | 
					extern bool	toutkeep;
 | 
				
			||||||
 | 
					extern bool	trejkeep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEBUGGING
 | 
				
			||||||
 | 
					extern int	debug;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern bool	force;
 | 
				
			||||||
 | 
					extern bool	batch;
 | 
				
			||||||
 | 
					extern bool	verbose;
 | 
				
			||||||
 | 
					extern bool	reverse;
 | 
				
			||||||
 | 
					extern bool	noreverse;
 | 
				
			||||||
 | 
					extern bool	skip_rest_of_patch;
 | 
				
			||||||
 | 
					extern int	strippath;
 | 
				
			||||||
 | 
					extern bool	canonicalize;
 | 
				
			||||||
 | 
					/* TRUE if -C was specified on command line.  */
 | 
				
			||||||
 | 
					extern bool	check_only;
 | 
				
			||||||
 | 
					extern bool	warn_on_invalid_line;
 | 
				
			||||||
 | 
					extern bool	last_line_missing_eol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CONTEXT_DIFF 1
 | 
				
			||||||
 | 
					#define NORMAL_DIFF 2
 | 
				
			||||||
 | 
					#define ED_DIFF 3
 | 
				
			||||||
 | 
					#define NEW_CONTEXT_DIFF 4
 | 
				
			||||||
 | 
					#define UNI_DIFF 5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int	diff_type;
 | 
				
			||||||
 | 
					extern char	*revision;	/* prerequisite revision, if any */
 | 
				
			||||||
 | 
					extern LINENUM	input_lines;	/* how long is input file in lines */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int	posix;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										486
									
								
								commands/patch/inp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										486
									
								
								commands/patch/inp.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,486 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * $OpenBSD: inp.c,v 1.34 2006/03/11 19:41:30 otto Exp $
 | 
				
			||||||
 | 
					 * $DragonFly: src/usr.bin/patch/inp.c,v 1.6 2007/09/29 23:11:10 swildner Exp $
 | 
				
			||||||
 | 
					 * $NetBSD: inp.c,v 1.19 2008/09/19 18:33:34 joerg Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * patch - a program to apply diffs to original files
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Copyright 1986, Larry Wall
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					 * modification, are permitted provided that the following condition is met:
 | 
				
			||||||
 | 
					 * 1. Redistributions of source code must retain the above copyright notice,
 | 
				
			||||||
 | 
					 * this condition and the following disclaimer.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
 | 
				
			||||||
 | 
					 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
				
			||||||
 | 
					 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
				
			||||||
 | 
					 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
				
			||||||
 | 
					 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
				
			||||||
 | 
					 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
				
			||||||
 | 
					 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
				
			||||||
 | 
					 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
				
			||||||
 | 
					 * SUCH DAMAGE.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * -C option added in 1998, original code by Marc Espie, based on FreeBSD
 | 
				
			||||||
 | 
					 * behaviour
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sys/cdefs.h>
 | 
				
			||||||
 | 
					__RCSID("$NetBSD: inp.c,v 1.19 2008/09/19 18:33:34 joerg Exp $");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					#include <sys/file.h>
 | 
				
			||||||
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					#include <sys/mman.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					#include <libgen.h>
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "common.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					#include "pch.h"
 | 
				
			||||||
 | 
					#include "inp.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Input-file-with-indexable-lines abstract type */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static off_t	i_size;		/* size of the input file */
 | 
				
			||||||
 | 
					static char	*i_womp;	/* plan a buffer for entire file */
 | 
				
			||||||
 | 
					static char	**i_ptr;	/* pointers to lines in i_womp */
 | 
				
			||||||
 | 
					static char	empty_line[] = { '\0' };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int	tifd = -1;	/* plan b virtual string array */
 | 
				
			||||||
 | 
					static char	*tibuf[2];	/* plan b buffers */
 | 
				
			||||||
 | 
					static LINENUM	tiline[2] = {-1, -1};	/* 1st line in each buffer */
 | 
				
			||||||
 | 
					static LINENUM	lines_per_buf;	/* how many lines per buffer */
 | 
				
			||||||
 | 
					static int	tireclen;	/* length of records in tmp file */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool	rev_in_string(const char *);
 | 
				
			||||||
 | 
					static bool	reallocate_lines(size_t *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* returns false if insufficient memory */
 | 
				
			||||||
 | 
					static bool	plan_a(const char *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void	plan_b(const char *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* New patch--prepare to edit another file. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					re_input(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (using_plan_a) {
 | 
				
			||||||
 | 
							i_size = 0;
 | 
				
			||||||
 | 
							free(i_ptr);
 | 
				
			||||||
 | 
							i_ptr = NULL;
 | 
				
			||||||
 | 
							if (i_womp != NULL) {
 | 
				
			||||||
 | 
								munmap(i_womp, i_size);
 | 
				
			||||||
 | 
								i_womp = NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							using_plan_a = true;	/* maybe the next one is smaller */
 | 
				
			||||||
 | 
							close(tifd);
 | 
				
			||||||
 | 
							tifd = -1;
 | 
				
			||||||
 | 
							free(tibuf[0]);
 | 
				
			||||||
 | 
							free(tibuf[1]);
 | 
				
			||||||
 | 
							tibuf[0] = tibuf[1] = NULL;
 | 
				
			||||||
 | 
							tiline[0] = tiline[1] = -1;
 | 
				
			||||||
 | 
							tireclen = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Construct the line index, somehow or other. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					scan_input(const char *filename)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!plan_a(filename))
 | 
				
			||||||
 | 
							plan_b(filename);
 | 
				
			||||||
 | 
						if (verbose) {
 | 
				
			||||||
 | 
							say("Patching file %s using Plan %s...\n", filename,
 | 
				
			||||||
 | 
							    (using_plan_a ? "A" : "B"));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool
 | 
				
			||||||
 | 
					reallocate_lines(size_t *lines_allocated)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char	**p;
 | 
				
			||||||
 | 
						size_t	new_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						new_size = *lines_allocated * 3 / 2;
 | 
				
			||||||
 | 
						p = realloc(i_ptr, (new_size + 2) * sizeof(char *));
 | 
				
			||||||
 | 
						if (p == NULL) {	/* shucks, it was a near thing */
 | 
				
			||||||
 | 
							munmap(i_womp, i_size);
 | 
				
			||||||
 | 
							i_womp = NULL;
 | 
				
			||||||
 | 
							free(i_ptr);
 | 
				
			||||||
 | 
							i_ptr = NULL;
 | 
				
			||||||
 | 
							*lines_allocated = 0;
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						*lines_allocated = new_size;
 | 
				
			||||||
 | 
						i_ptr = p;
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Try keeping everything in memory. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool
 | 
				
			||||||
 | 
					plan_a(const char *filename)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int		ifd, statfailed;
 | 
				
			||||||
 | 
						char		*p, *s, lbuf[MAXLINELEN];
 | 
				
			||||||
 | 
						struct stat	filestat;
 | 
				
			||||||
 | 
						off_t		i;
 | 
				
			||||||
 | 
						ptrdiff_t	sz;
 | 
				
			||||||
 | 
						size_t		iline, lines_allocated;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEBUGGING
 | 
				
			||||||
 | 
						if (debug & 8)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (filename == NULL || *filename == '\0')
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						statfailed = stat(filename, &filestat);
 | 
				
			||||||
 | 
						if (statfailed && ok_to_create_file) {
 | 
				
			||||||
 | 
							if (verbose)
 | 
				
			||||||
 | 
								say("(Creating file %s...)\n", filename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * in check_patch case, we still display `Creating file' even
 | 
				
			||||||
 | 
							 * though we're not. The rule is that -C should be as similar
 | 
				
			||||||
 | 
							 * to normal patch behavior as possible
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (check_only)
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							makedirs(filename, true);
 | 
				
			||||||
 | 
							close(creat(filename, 0666));
 | 
				
			||||||
 | 
							statfailed = stat(filename, &filestat);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (statfailed && check_only)
 | 
				
			||||||
 | 
							fatal("%s not found, -C mode, can't probe further\n", filename);
 | 
				
			||||||
 | 
						/* For nonexistent or read-only files, look for RCS or SCCS versions.  */
 | 
				
			||||||
 | 
						if (statfailed ||
 | 
				
			||||||
 | 
						    /* No one can write to it.  */
 | 
				
			||||||
 | 
						    (filestat.st_mode & 0222) == 0 ||
 | 
				
			||||||
 | 
						    /* I can't write to it.  */
 | 
				
			||||||
 | 
						    ((filestat.st_mode & 0022) == 0 && filestat.st_uid != getuid())) {
 | 
				
			||||||
 | 
							const char	*cs = NULL, *filebase, *filedir;
 | 
				
			||||||
 | 
							struct stat	cstat;
 | 
				
			||||||
 | 
							char *tmp_filename1, *tmp_filename2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							tmp_filename1 = strdup(filename);
 | 
				
			||||||
 | 
							tmp_filename2 = strdup(filename);
 | 
				
			||||||
 | 
							if (tmp_filename1 == NULL || tmp_filename2 == NULL)
 | 
				
			||||||
 | 
								fatal("strdupping filename");
 | 
				
			||||||
 | 
							filebase = basename(tmp_filename1);
 | 
				
			||||||
 | 
							filedir = dirname(tmp_filename2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Leave room in lbuf for the diff command.  */
 | 
				
			||||||
 | 
							s = lbuf + 20;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define try(f, a1, a2, a3) \
 | 
				
			||||||
 | 
						(snprintf(s, sizeof lbuf - 20, f, a1, a2, a3), stat(s, &cstat) == 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX) ||
 | 
				
			||||||
 | 
							    try("%s/RCS/%s%s", filedir, filebase, "") ||
 | 
				
			||||||
 | 
							    try("%s/%s%s", filedir, filebase, RCSSUFFIX)) {
 | 
				
			||||||
 | 
								snprintf(buf, buf_len, CHECKOUT, filename);
 | 
				
			||||||
 | 
								snprintf(lbuf, sizeof lbuf, RCSDIFF, filename);
 | 
				
			||||||
 | 
								cs = "RCS";
 | 
				
			||||||
 | 
							} else if (try("%s/SCCS/%s%s", filedir, SCCSPREFIX, filebase) ||
 | 
				
			||||||
 | 
							    try("%s/%s%s", filedir, SCCSPREFIX, filebase)) {
 | 
				
			||||||
 | 
								snprintf(buf, buf_len, GET, s);
 | 
				
			||||||
 | 
								snprintf(lbuf, sizeof lbuf, SCCSDIFF, s, filename);
 | 
				
			||||||
 | 
								cs = "SCCS";
 | 
				
			||||||
 | 
							} else if (statfailed)
 | 
				
			||||||
 | 
								fatal("can't find %s\n", filename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							free(tmp_filename1);
 | 
				
			||||||
 | 
							free(tmp_filename2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * else we can't write to it but it's not under a version
 | 
				
			||||||
 | 
							 * control system, so just proceed.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (cs) {
 | 
				
			||||||
 | 
								if (!statfailed) {
 | 
				
			||||||
 | 
									if ((filestat.st_mode & 0222) != 0)
 | 
				
			||||||
 | 
										/* The owner can write to it.  */
 | 
				
			||||||
 | 
										fatal("file %s seems to be locked "
 | 
				
			||||||
 | 
										    "by somebody else under %s\n",
 | 
				
			||||||
 | 
										    filename, cs);
 | 
				
			||||||
 | 
									/*
 | 
				
			||||||
 | 
									 * It might be checked out unlocked.  See if
 | 
				
			||||||
 | 
									 * it's safe to check out the default version
 | 
				
			||||||
 | 
									 * locked.
 | 
				
			||||||
 | 
									 */
 | 
				
			||||||
 | 
									if (verbose)
 | 
				
			||||||
 | 
										say("Comparing file %s to default "
 | 
				
			||||||
 | 
										    "%s version...\n",
 | 
				
			||||||
 | 
										    filename, cs);
 | 
				
			||||||
 | 
									if (system(lbuf))
 | 
				
			||||||
 | 
										fatal("can't check out file %s: "
 | 
				
			||||||
 | 
										    "differs from default %s version\n",
 | 
				
			||||||
 | 
										    filename, cs);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (verbose)
 | 
				
			||||||
 | 
									say("Checking out file %s from %s...\n",
 | 
				
			||||||
 | 
									    filename, cs);
 | 
				
			||||||
 | 
								if (system(buf) || stat(filename, &filestat))
 | 
				
			||||||
 | 
									fatal("can't check out file %s from %s\n",
 | 
				
			||||||
 | 
									    filename, cs);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						filemode = filestat.st_mode;
 | 
				
			||||||
 | 
						if (!S_ISREG(filemode))
 | 
				
			||||||
 | 
							fatal("%s is not a normal file--can't patch\n", filename);
 | 
				
			||||||
 | 
						i_size = filestat.st_size;
 | 
				
			||||||
 | 
						if (out_of_mem) {
 | 
				
			||||||
 | 
							set_hunkmax();	/* make sure dynamic arrays are allocated */
 | 
				
			||||||
 | 
							out_of_mem = false;
 | 
				
			||||||
 | 
							return false;	/* force plan b because plan a bombed */
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (i_size > SIZE_MAX) {
 | 
				
			||||||
 | 
							say("block too large to mmap\n");
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if ((ifd = open(filename, O_RDONLY)) < 0)
 | 
				
			||||||
 | 
							pfatal("can't open file %s", filename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						i_womp = mmap(NULL, i_size, PROT_READ, MAP_PRIVATE, ifd, 0);
 | 
				
			||||||
 | 
						if (i_womp == MAP_FAILED) {
 | 
				
			||||||
 | 
							perror("mmap failed");
 | 
				
			||||||
 | 
							i_womp = NULL;
 | 
				
			||||||
 | 
							close(ifd);
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						close(ifd);
 | 
				
			||||||
 | 
						if (i_size)
 | 
				
			||||||
 | 
							madvise(i_womp, i_size, MADV_SEQUENTIAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* estimate the number of lines */
 | 
				
			||||||
 | 
						lines_allocated = i_size / 25;
 | 
				
			||||||
 | 
						if (lines_allocated < 100)
 | 
				
			||||||
 | 
							lines_allocated = 100;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!reallocate_lines(&lines_allocated))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* now scan the buffer and build pointer array */
 | 
				
			||||||
 | 
						iline = 1;
 | 
				
			||||||
 | 
						i_ptr[iline] = i_womp;
 | 
				
			||||||
 | 
						/* test for NUL too, to maintain the behavior of the original code */
 | 
				
			||||||
 | 
						for (s = i_womp, i = 0; i < i_size && *s != '\0'; s++, i++) {
 | 
				
			||||||
 | 
							if (*s == '\n') {
 | 
				
			||||||
 | 
								if (iline == lines_allocated) {
 | 
				
			||||||
 | 
									if (!reallocate_lines(&lines_allocated))
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								/* these are NOT NUL terminated */
 | 
				
			||||||
 | 
								i_ptr[++iline] = s + 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						/* if the last line contains no EOL, append one */
 | 
				
			||||||
 | 
						if (i_size > 0 && i_womp[i_size - 1] != '\n') {
 | 
				
			||||||
 | 
							last_line_missing_eol = true;
 | 
				
			||||||
 | 
							/* fix last line */
 | 
				
			||||||
 | 
							sz = s - i_ptr[iline];
 | 
				
			||||||
 | 
							p = malloc(sz + 1);
 | 
				
			||||||
 | 
							if (p == NULL) {
 | 
				
			||||||
 | 
								free(i_ptr);
 | 
				
			||||||
 | 
								i_ptr = NULL;
 | 
				
			||||||
 | 
								munmap(i_womp, i_size);
 | 
				
			||||||
 | 
								i_womp = NULL;
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							memcpy(p, i_ptr[iline], sz);
 | 
				
			||||||
 | 
							p[sz] = '\n';
 | 
				
			||||||
 | 
							i_ptr[iline] = p;
 | 
				
			||||||
 | 
							/* count the extra line and make it point to some valid mem */
 | 
				
			||||||
 | 
							i_ptr[++iline] = empty_line;
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							last_line_missing_eol = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_lines = iline - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* now check for revision, if any */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (revision != NULL) {
 | 
				
			||||||
 | 
							if (!rev_in_string(i_womp)) {
 | 
				
			||||||
 | 
								if (force) {
 | 
				
			||||||
 | 
									if (verbose)
 | 
				
			||||||
 | 
										say("Warning: this file doesn't appear "
 | 
				
			||||||
 | 
										    "to be the %s version--patching anyway.\n",
 | 
				
			||||||
 | 
										    revision);
 | 
				
			||||||
 | 
								} else if (batch) {
 | 
				
			||||||
 | 
									fatal("this file doesn't appear to be the "
 | 
				
			||||||
 | 
									    "%s version--aborting.\n",
 | 
				
			||||||
 | 
									    revision);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									ask("This file doesn't appear to be the "
 | 
				
			||||||
 | 
									    "%s version--patch anyway? [n] ",
 | 
				
			||||||
 | 
									    revision);
 | 
				
			||||||
 | 
									if (*buf != 'y')
 | 
				
			||||||
 | 
										fatal("aborted\n");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else if (verbose)
 | 
				
			||||||
 | 
								say("Good.  This file appears to be the %s version.\n",
 | 
				
			||||||
 | 
								    revision);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return true;		/* plan a will work */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Keep (virtually) nothing in memory. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					plan_b(const char *filename)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						FILE	*ifp;
 | 
				
			||||||
 | 
						size_t	i = 0, j, maxlen = 1;
 | 
				
			||||||
 | 
						char	*p;
 | 
				
			||||||
 | 
						bool	found_revision = (revision == NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						using_plan_a = false;
 | 
				
			||||||
 | 
						if ((ifp = fopen(filename, "r")) == NULL)
 | 
				
			||||||
 | 
							pfatal("can't open file %s", filename);
 | 
				
			||||||
 | 
						unlink(TMPINNAME);
 | 
				
			||||||
 | 
						if ((tifd = open(TMPINNAME, O_EXCL | O_CREAT | O_WRONLY, 0666)) < 0)
 | 
				
			||||||
 | 
							pfatal("can't open file %s", TMPINNAME);
 | 
				
			||||||
 | 
						while (fgets(buf, buf_len, ifp) != NULL) {
 | 
				
			||||||
 | 
							if (revision != NULL && !found_revision && rev_in_string(buf))
 | 
				
			||||||
 | 
								found_revision = true;
 | 
				
			||||||
 | 
							if ((i = strlen(buf)) > maxlen)
 | 
				
			||||||
 | 
								maxlen = i;	/* find longest line */
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						last_line_missing_eol = i > 0 && buf[i - 1] != '\n';
 | 
				
			||||||
 | 
						if (last_line_missing_eol && maxlen == i)
 | 
				
			||||||
 | 
							maxlen++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (revision != NULL) {
 | 
				
			||||||
 | 
							if (!found_revision) {
 | 
				
			||||||
 | 
								if (force) {
 | 
				
			||||||
 | 
									if (verbose)
 | 
				
			||||||
 | 
										say("Warning: this file doesn't appear "
 | 
				
			||||||
 | 
										    "to be the %s version--patching anyway.\n",
 | 
				
			||||||
 | 
										    revision);
 | 
				
			||||||
 | 
								} else if (batch) {
 | 
				
			||||||
 | 
									fatal("this file doesn't appear to be the "
 | 
				
			||||||
 | 
									    "%s version--aborting.\n",
 | 
				
			||||||
 | 
									    revision);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									ask("This file doesn't appear to be the %s "
 | 
				
			||||||
 | 
									    "version--patch anyway? [n] ",
 | 
				
			||||||
 | 
									    revision);
 | 
				
			||||||
 | 
									if (*buf != 'y')
 | 
				
			||||||
 | 
										fatal("aborted\n");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else if (verbose)
 | 
				
			||||||
 | 
								say("Good.  This file appears to be the %s version.\n",
 | 
				
			||||||
 | 
								    revision);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						fseek(ifp, 0L, SEEK_SET);	/* rewind file */
 | 
				
			||||||
 | 
						lines_per_buf = BUFFERSIZE / maxlen;
 | 
				
			||||||
 | 
						tireclen = maxlen;
 | 
				
			||||||
 | 
						tibuf[0] = malloc(BUFFERSIZE + 1);
 | 
				
			||||||
 | 
						if (tibuf[0] == NULL)
 | 
				
			||||||
 | 
							fatal("out of memory\n");
 | 
				
			||||||
 | 
						tibuf[1] = malloc(BUFFERSIZE + 1);
 | 
				
			||||||
 | 
						if (tibuf[1] == NULL)
 | 
				
			||||||
 | 
							fatal("out of memory\n");
 | 
				
			||||||
 | 
						for (i = 1;; i++) {
 | 
				
			||||||
 | 
							p = tibuf[0] + maxlen * (i % lines_per_buf);
 | 
				
			||||||
 | 
							if (i % lines_per_buf == 0)	/* new block */
 | 
				
			||||||
 | 
								if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
 | 
				
			||||||
 | 
									pfatal("can't write temp file");
 | 
				
			||||||
 | 
							if (fgets(p, maxlen + 1, ifp) == NULL) {
 | 
				
			||||||
 | 
								input_lines = i - 1;
 | 
				
			||||||
 | 
								if (i % lines_per_buf != 0)
 | 
				
			||||||
 | 
									if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
 | 
				
			||||||
 | 
										pfatal("can't write temp file");
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							j = strlen(p);
 | 
				
			||||||
 | 
							/* These are '\n' terminated strings, so no need to add a NUL */
 | 
				
			||||||
 | 
							if (j == 0 || p[j - 1] != '\n')
 | 
				
			||||||
 | 
								p[j] = '\n';
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						fclose(ifp);
 | 
				
			||||||
 | 
						close(tifd);
 | 
				
			||||||
 | 
						if ((tifd = open(TMPINNAME, O_RDONLY)) < 0)
 | 
				
			||||||
 | 
							pfatal("can't reopen file %s", TMPINNAME);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Fetch a line from the input file, \n terminated, not necessarily \0.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					char *
 | 
				
			||||||
 | 
					ifetch(LINENUM line, int whichbuf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (line < 1 || line > input_lines) {
 | 
				
			||||||
 | 
							if (warn_on_invalid_line) {
 | 
				
			||||||
 | 
								say("No such line %ld in input file, ignoring\n", line);
 | 
				
			||||||
 | 
								warn_on_invalid_line = false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (using_plan_a)
 | 
				
			||||||
 | 
							return i_ptr[line];
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
							LINENUM	offline = line % lines_per_buf;
 | 
				
			||||||
 | 
							LINENUM	baseline = line - offline;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (tiline[0] == baseline)
 | 
				
			||||||
 | 
								whichbuf = 0;
 | 
				
			||||||
 | 
							else if (tiline[1] == baseline)
 | 
				
			||||||
 | 
								whichbuf = 1;
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								tiline[whichbuf] = baseline;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (lseek(tifd, (off_t) (baseline / lines_per_buf *
 | 
				
			||||||
 | 
								    BUFFERSIZE), SEEK_SET) < 0)
 | 
				
			||||||
 | 
									pfatal("cannot seek in the temporary input file");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (read(tifd, tibuf[whichbuf], BUFFERSIZE) < 0)
 | 
				
			||||||
 | 
									pfatal("error reading tmp file %s", TMPINNAME);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return tibuf[whichbuf] + (tireclen * offline);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * True if the string argument contains the revision number we want.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static bool
 | 
				
			||||||
 | 
					rev_in_string(const char *string)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const char	*s;
 | 
				
			||||||
 | 
						size_t		patlen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (revision == NULL)
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						patlen = strlen(revision);
 | 
				
			||||||
 | 
						if (strnEQ(string, revision, patlen) && isspace((unsigned char)string[patlen]))
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						for (s = string; *s; s++) {
 | 
				
			||||||
 | 
							if (isspace((unsigned char)*s) && strnEQ(s + 1, revision, patlen) &&
 | 
				
			||||||
 | 
							    isspace((unsigned char)s[patlen + 1])) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										35
									
								
								commands/patch/inp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								commands/patch/inp.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * $OpenBSD: inp.h,v 1.8 2003/08/15 08:00:51 otto Exp $
 | 
				
			||||||
 | 
					 * $DragonFly: src/usr.bin/patch/inp.h,v 1.1 2004/09/24 18:44:28 joerg Exp $
 | 
				
			||||||
 | 
					 * $NetBSD: inp.h,v 1.10 2008/09/19 18:33:34 joerg Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * patch - a program to apply diffs to original files
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Copyright 1986, Larry Wall
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					 * modification, are permitted provided that the following condition is met:
 | 
				
			||||||
 | 
					 * 1. Redistributions of source code must retain the above copyright notice,
 | 
				
			||||||
 | 
					 * this condition and the following disclaimer.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
 | 
				
			||||||
 | 
					 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
				
			||||||
 | 
					 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
				
			||||||
 | 
					 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
				
			||||||
 | 
					 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
				
			||||||
 | 
					 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
				
			||||||
 | 
					 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
				
			||||||
 | 
					 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
				
			||||||
 | 
					 * SUCH DAMAGE.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * -C option added in 1998, original code by Marc Espie, based on FreeBSD
 | 
				
			||||||
 | 
					 * behaviour
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void		re_input(void);
 | 
				
			||||||
 | 
					void		scan_input(const char *);
 | 
				
			||||||
 | 
					char		*ifetch(LINENUM, int);
 | 
				
			||||||
							
								
								
									
										84
									
								
								commands/patch/mkpath.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								commands/patch/mkpath.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,84 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *	$OpenBSD: mkpath.c,v 1.2 2005/06/20 07:14:06 otto Exp $
 | 
				
			||||||
 | 
					 *	$DragonFly: src/usr.bin/patch/mkpath.c,v 1.1 2007/09/29 23:11:10 swildner Exp $
 | 
				
			||||||
 | 
					 *	$NetBSD: mkpath.c,v 1.1 2008/09/19 18:33:34 joerg Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) 1983, 1992, 1993
 | 
				
			||||||
 | 
					 *	The Regents of the University of California.  All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					 * modification, are permitted provided that the following conditions
 | 
				
			||||||
 | 
					 * are met:
 | 
				
			||||||
 | 
					 * 1. Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					 *    notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					 * 2. Redistributions in binary form must reproduce the above copyright
 | 
				
			||||||
 | 
					 *    notice, this list of conditions and the following disclaimer in the
 | 
				
			||||||
 | 
					 *    documentation and/or other materials provided with the distribution.
 | 
				
			||||||
 | 
					 * 3. Neither the name of the University nor the names of its contributors
 | 
				
			||||||
 | 
					 *    may be used to endorse or promote products derived from this software
 | 
				
			||||||
 | 
					 *    without specific prior written permission.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 | 
				
			||||||
 | 
					 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
				
			||||||
 | 
					 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
				
			||||||
 | 
					 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 | 
				
			||||||
 | 
					 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
				
			||||||
 | 
					 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
				
			||||||
 | 
					 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
				
			||||||
 | 
					 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
				
			||||||
 | 
					 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
				
			||||||
 | 
					 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
				
			||||||
 | 
					 * SUCH DAMAGE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sys/cdefs.h>
 | 
				
			||||||
 | 
					__RCSID("$NetBSD: mkpath.c,v 1.1 2008/09/19 18:33:34 joerg Exp $");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					#include <err.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int	mkpath(char *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Code taken directly from mkdir(1).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * mkpath -- create directories.
 | 
				
			||||||
 | 
					 *	path     - path
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					mkpath(char *path)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct stat sb;
 | 
				
			||||||
 | 
						char *slash;
 | 
				
			||||||
 | 
						int done = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						slash = path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (!done) {
 | 
				
			||||||
 | 
							slash += strspn(slash, "/");
 | 
				
			||||||
 | 
							slash += strcspn(slash, "/");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							done = (*slash == '\0');
 | 
				
			||||||
 | 
							*slash = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (stat(path, &sb)) {
 | 
				
			||||||
 | 
								if (errno != ENOENT || (mkdir(path, 0777) &&
 | 
				
			||||||
 | 
								    errno != EEXIST)) {
 | 
				
			||||||
 | 
									warn("%s", path);
 | 
				
			||||||
 | 
									return (-1);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else if (!S_ISDIR(sb.st_mode)) {
 | 
				
			||||||
 | 
								warnx("%s: %s", path, strerror(ENOTDIR));
 | 
				
			||||||
 | 
								return (-1);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							*slash = '/';
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return (0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										700
									
								
								commands/patch/patch.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										700
									
								
								commands/patch/patch.1
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,700 @@
 | 
				
			|||||||
 | 
					.\"	$OpenBSD: patch.1,v 1.22 2008/06/06 20:44:00 jmc Exp $
 | 
				
			||||||
 | 
					.\"	$DragonFly: src/usr.bin/patch/patch.1,v 1.10 2008/08/18 19:15:55 joerg Exp $
 | 
				
			||||||
 | 
					.\"	$NetBSD: patch.1,v 1.13 2008/09/19 18:33:34 joerg Exp $
 | 
				
			||||||
 | 
					.\" Copyright 1986, Larry Wall
 | 
				
			||||||
 | 
					.\"
 | 
				
			||||||
 | 
					.\" Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					.\" modification, are permitted provided that the following condition
 | 
				
			||||||
 | 
					.\" is met:
 | 
				
			||||||
 | 
					.\"  1. Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					.\"     notice, this condition and the following disclaimer.
 | 
				
			||||||
 | 
					.\"
 | 
				
			||||||
 | 
					.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 | 
				
			||||||
 | 
					.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
				
			||||||
 | 
					.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
				
			||||||
 | 
					.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 | 
				
			||||||
 | 
					.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
				
			||||||
 | 
					.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
				
			||||||
 | 
					.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
				
			||||||
 | 
					.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
				
			||||||
 | 
					.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
				
			||||||
 | 
					.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
				
			||||||
 | 
					.\" SUCH DAMAGE.
 | 
				
			||||||
 | 
					.\"
 | 
				
			||||||
 | 
					.Dd August 18, 2008
 | 
				
			||||||
 | 
					.Dt PATCH 1
 | 
				
			||||||
 | 
					.Os
 | 
				
			||||||
 | 
					.Sh NAME
 | 
				
			||||||
 | 
					.Nm patch
 | 
				
			||||||
 | 
					.Nd apply a diff file to an original
 | 
				
			||||||
 | 
					.Sh SYNOPSIS
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					.Bk -words
 | 
				
			||||||
 | 
					.Op Fl bCcEeflNnRstuv
 | 
				
			||||||
 | 
					.Op Fl B Ar backup-prefix
 | 
				
			||||||
 | 
					.Op Fl D Ar symbol
 | 
				
			||||||
 | 
					.Op Fl d Ar directory
 | 
				
			||||||
 | 
					.Op Fl F Ar max-fuzz
 | 
				
			||||||
 | 
					.Op Fl i Ar patchfile
 | 
				
			||||||
 | 
					.Op Fl o Ar out-file
 | 
				
			||||||
 | 
					.Op Fl p Ar strip-count
 | 
				
			||||||
 | 
					.Op Fl r Ar rej-name
 | 
				
			||||||
 | 
					.Op Fl V Cm t | nil | never
 | 
				
			||||||
 | 
					.Op Fl x Ar number
 | 
				
			||||||
 | 
					.Op Fl z Ar backup-ext
 | 
				
			||||||
 | 
					.Op Fl Fl posix
 | 
				
			||||||
 | 
					.Op Ar origfile Op Ar patchfile
 | 
				
			||||||
 | 
					.Ek
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					.Pf \*(Lt Ar patchfile
 | 
				
			||||||
 | 
					.Sh DESCRIPTION
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					will take a patch file containing any of the four forms of difference
 | 
				
			||||||
 | 
					listing produced by the
 | 
				
			||||||
 | 
					.Xr diff 1
 | 
				
			||||||
 | 
					program and apply those differences to an original file,
 | 
				
			||||||
 | 
					producing a patched version.
 | 
				
			||||||
 | 
					If
 | 
				
			||||||
 | 
					.Ar patchfile
 | 
				
			||||||
 | 
					is omitted, or is a hyphen, the patch will be read from the standard input.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					will attempt to determine the type of the diff listing, unless over-ruled by a
 | 
				
			||||||
 | 
					.Fl c ,
 | 
				
			||||||
 | 
					.Fl e ,
 | 
				
			||||||
 | 
					.Fl n ,
 | 
				
			||||||
 | 
					or
 | 
				
			||||||
 | 
					.Fl u
 | 
				
			||||||
 | 
					option.
 | 
				
			||||||
 | 
					Context diffs (old-style, new-style, and unified) and
 | 
				
			||||||
 | 
					normal diffs are applied directly by the
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					program itself, whereas ed diffs are simply fed to the
 | 
				
			||||||
 | 
					.Xr ed 1
 | 
				
			||||||
 | 
					editor via a pipe.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					If the
 | 
				
			||||||
 | 
					.Ar patchfile
 | 
				
			||||||
 | 
					contains more than one patch,
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					will try to apply each of them as if they came from separate patch files.
 | 
				
			||||||
 | 
					This means, among other things, that it is assumed that the name of the file
 | 
				
			||||||
 | 
					to patch must be determined for each diff listing, and that the garbage before
 | 
				
			||||||
 | 
					each diff listing will be examined for interesting things such as file names
 | 
				
			||||||
 | 
					and revision level (see the section on
 | 
				
			||||||
 | 
					.Sx Filename Determination
 | 
				
			||||||
 | 
					below).
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					The options are as follows:
 | 
				
			||||||
 | 
					.Bl -tag -width Ds
 | 
				
			||||||
 | 
					.It Xo
 | 
				
			||||||
 | 
					.Fl B Ar backup-prefix ,
 | 
				
			||||||
 | 
					.Fl Fl prefix Ar backup-prefix
 | 
				
			||||||
 | 
					.Xc
 | 
				
			||||||
 | 
					Causes the next argument to be interpreted as a prefix to the backup file
 | 
				
			||||||
 | 
					name.
 | 
				
			||||||
 | 
					If this argument is specified, any argument to
 | 
				
			||||||
 | 
					.Fl z
 | 
				
			||||||
 | 
					will be ignored.
 | 
				
			||||||
 | 
					.It Fl b , Fl Fl backup
 | 
				
			||||||
 | 
					Save a backup copy of the file before it is modified.
 | 
				
			||||||
 | 
					By default the original file is saved with a backup extension of
 | 
				
			||||||
 | 
					.Qq .orig
 | 
				
			||||||
 | 
					unless the file already has a numbered backup, in which case a numbered
 | 
				
			||||||
 | 
					backup is made.
 | 
				
			||||||
 | 
					This is equivalent to specifying
 | 
				
			||||||
 | 
					.Qo Fl V Cm existing Qc .
 | 
				
			||||||
 | 
					This option is currently the default, unless
 | 
				
			||||||
 | 
					.Fl -posix
 | 
				
			||||||
 | 
					is specified.
 | 
				
			||||||
 | 
					.It Fl C , Fl Fl check
 | 
				
			||||||
 | 
					Checks that the patch would apply cleanly, but does not modify anything.
 | 
				
			||||||
 | 
					.It Fl c , Fl Fl context
 | 
				
			||||||
 | 
					Forces
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					to interpret the patch file as a context diff.
 | 
				
			||||||
 | 
					.It Xo
 | 
				
			||||||
 | 
					.Fl D Ar symbol ,
 | 
				
			||||||
 | 
					.Fl Fl ifdef Ar symbol
 | 
				
			||||||
 | 
					.Xc
 | 
				
			||||||
 | 
					Causes
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					to use the
 | 
				
			||||||
 | 
					.Qq #ifdef...#endif
 | 
				
			||||||
 | 
					construct to mark changes.
 | 
				
			||||||
 | 
					The argument following will be used as the differentiating symbol.
 | 
				
			||||||
 | 
					Note that, unlike the C compiler, there must be a space between the
 | 
				
			||||||
 | 
					.Fl D
 | 
				
			||||||
 | 
					and the argument.
 | 
				
			||||||
 | 
					.It Xo
 | 
				
			||||||
 | 
					.Fl d Ar directory ,
 | 
				
			||||||
 | 
					.Fl Fl directory Ar directory
 | 
				
			||||||
 | 
					.Xc
 | 
				
			||||||
 | 
					Causes
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					to interpret the next argument as a directory,
 | 
				
			||||||
 | 
					and change the working directory to it before doing anything else.
 | 
				
			||||||
 | 
					.It Fl E , Fl Fl remove-empty-files
 | 
				
			||||||
 | 
					Causes
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					to remove output files that are empty after the patches have been applied.
 | 
				
			||||||
 | 
					This option is useful when applying patches that create or remove files.
 | 
				
			||||||
 | 
					.It Fl e , Fl Fl ed
 | 
				
			||||||
 | 
					Forces
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					to interpret the patch file as an
 | 
				
			||||||
 | 
					.Xr ed 1
 | 
				
			||||||
 | 
					script.
 | 
				
			||||||
 | 
					.It Xo
 | 
				
			||||||
 | 
					.Fl F Ar max-fuzz ,
 | 
				
			||||||
 | 
					.Fl Fl fuzz Ar max-fuzz
 | 
				
			||||||
 | 
					.Xc
 | 
				
			||||||
 | 
					Sets the maximum fuzz factor.
 | 
				
			||||||
 | 
					This option only applies to context diffs, and causes
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					to ignore up to that many lines in looking for places to install a hunk.
 | 
				
			||||||
 | 
					Note that a larger fuzz factor increases the odds of a faulty patch.
 | 
				
			||||||
 | 
					The default fuzz factor is 2, and it may not be set to more than
 | 
				
			||||||
 | 
					the number of lines of context in the context diff, ordinarily 3.
 | 
				
			||||||
 | 
					.It Fl f , Fl Fl force
 | 
				
			||||||
 | 
					Forces
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					to assume that the user knows exactly what he or she is doing, and to not
 | 
				
			||||||
 | 
					ask any questions.
 | 
				
			||||||
 | 
					It assumes the following:
 | 
				
			||||||
 | 
					skip patches for which a file to patch can't be found;
 | 
				
			||||||
 | 
					patch files even though they have the wrong version for the
 | 
				
			||||||
 | 
					.Qq Prereq:
 | 
				
			||||||
 | 
					line in the patch;
 | 
				
			||||||
 | 
					and assume that patches are not reversed even if they look like they are.
 | 
				
			||||||
 | 
					This option does not suppress commentary; use
 | 
				
			||||||
 | 
					.Fl s
 | 
				
			||||||
 | 
					for that.
 | 
				
			||||||
 | 
					.It Xo
 | 
				
			||||||
 | 
					.Fl i Ar patchfile ,
 | 
				
			||||||
 | 
					.Fl Fl input Ar patchfile
 | 
				
			||||||
 | 
					.Xc
 | 
				
			||||||
 | 
					Causes the next argument to be interpreted as the input file name
 | 
				
			||||||
 | 
					(i.e. a patchfile).
 | 
				
			||||||
 | 
					This option may be specified multiple times.
 | 
				
			||||||
 | 
					.It Fl l , Fl Fl ignore-whitespace
 | 
				
			||||||
 | 
					Causes the pattern matching to be done loosely, in case the tabs and
 | 
				
			||||||
 | 
					spaces have been munged in your input file.
 | 
				
			||||||
 | 
					Any sequence of whitespace in the pattern line will match any sequence
 | 
				
			||||||
 | 
					in the input file.
 | 
				
			||||||
 | 
					Normal characters must still match exactly.
 | 
				
			||||||
 | 
					Each line of the context must still match a line in the input file.
 | 
				
			||||||
 | 
					.It Fl N , Fl Fl forward
 | 
				
			||||||
 | 
					Causes
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					to ignore patches that it thinks are reversed or already applied.
 | 
				
			||||||
 | 
					See also
 | 
				
			||||||
 | 
					.Fl R .
 | 
				
			||||||
 | 
					.It Fl n , Fl Fl normal
 | 
				
			||||||
 | 
					Forces
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					to interpret the patch file as a normal diff.
 | 
				
			||||||
 | 
					.It Xo
 | 
				
			||||||
 | 
					.Fl o Ar out-file ,
 | 
				
			||||||
 | 
					.Fl Fl output Ar out-file
 | 
				
			||||||
 | 
					.Xc
 | 
				
			||||||
 | 
					Causes the next argument to be interpreted as the output file name.
 | 
				
			||||||
 | 
					.It Xo
 | 
				
			||||||
 | 
					.Fl p Ar strip-count ,
 | 
				
			||||||
 | 
					.Fl Fl strip Ar strip-count
 | 
				
			||||||
 | 
					.Xc
 | 
				
			||||||
 | 
					Sets the pathname strip count,
 | 
				
			||||||
 | 
					which controls how pathnames found in the patch file are treated,
 | 
				
			||||||
 | 
					in case you keep your files in a different directory than the person who sent
 | 
				
			||||||
 | 
					out the patch.
 | 
				
			||||||
 | 
					The strip count specifies how many slashes are to be stripped from
 | 
				
			||||||
 | 
					the front of the pathname.
 | 
				
			||||||
 | 
					(Any intervening directory names also go away.)
 | 
				
			||||||
 | 
					For example, supposing the file name in the patch file was
 | 
				
			||||||
 | 
					.Pa /u/howard/src/blurfl/blurfl.c :
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					Setting
 | 
				
			||||||
 | 
					.Fl p Ns Ar 0
 | 
				
			||||||
 | 
					gives the entire pathname unmodified.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					.Fl p Ns Ar 1
 | 
				
			||||||
 | 
					gives
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					.D1 Pa u/howard/src/blurfl/blurfl.c
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					without the leading slash.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					.Fl p Ns Ar 4
 | 
				
			||||||
 | 
					gives
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					.D1 Pa blurfl/blurfl.c
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					Not specifying
 | 
				
			||||||
 | 
					.Fl p
 | 
				
			||||||
 | 
					at all just gives you
 | 
				
			||||||
 | 
					.Pa blurfl.c ,
 | 
				
			||||||
 | 
					unless all of the directories in the leading path
 | 
				
			||||||
 | 
					.Pq Pa u/howard/src/blurfl
 | 
				
			||||||
 | 
					exist and that path is relative,
 | 
				
			||||||
 | 
					in which case you get the entire pathname unmodified.
 | 
				
			||||||
 | 
					Whatever you end up with is looked for either in the current directory,
 | 
				
			||||||
 | 
					or the directory specified by the
 | 
				
			||||||
 | 
					.Fl d
 | 
				
			||||||
 | 
					option.
 | 
				
			||||||
 | 
					.It Fl R , Fl Fl reverse
 | 
				
			||||||
 | 
					Tells
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					that this patch was created with the old and new files swapped.
 | 
				
			||||||
 | 
					(Yes, I'm afraid that does happen occasionally, human nature being what it
 | 
				
			||||||
 | 
					is.)
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					will attempt to swap each hunk around before applying it.
 | 
				
			||||||
 | 
					Rejects will come out in the swapped format.
 | 
				
			||||||
 | 
					The
 | 
				
			||||||
 | 
					.Fl R
 | 
				
			||||||
 | 
					option will not work with ed diff scripts because there is too little
 | 
				
			||||||
 | 
					information to reconstruct the reverse operation.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					If the first hunk of a patch fails,
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					will reverse the hunk to see if it can be applied that way.
 | 
				
			||||||
 | 
					If it can, you will be asked if you want to have the
 | 
				
			||||||
 | 
					.Fl R
 | 
				
			||||||
 | 
					option set.
 | 
				
			||||||
 | 
					If it can't, the patch will continue to be applied normally.
 | 
				
			||||||
 | 
					(Note: this method cannot detect a reversed patch if it is a normal diff
 | 
				
			||||||
 | 
					and if the first command is an append (i.e. it should have been a delete)
 | 
				
			||||||
 | 
					since appends always succeed, due to the fact that a null context will match
 | 
				
			||||||
 | 
					anywhere.
 | 
				
			||||||
 | 
					Luckily, most patches add or change lines rather than delete them, so most
 | 
				
			||||||
 | 
					reversed normal diffs will begin with a delete, which will fail, triggering
 | 
				
			||||||
 | 
					the heuristic.)
 | 
				
			||||||
 | 
					.It Xo
 | 
				
			||||||
 | 
					.Fl r Ar rej-name ,
 | 
				
			||||||
 | 
					.Fl Fl reject-file Ar rej-name
 | 
				
			||||||
 | 
					.Xc
 | 
				
			||||||
 | 
					Causes the next argument to be interpreted as the reject file name.
 | 
				
			||||||
 | 
					.It Xo
 | 
				
			||||||
 | 
					.Fl s , Fl Fl quiet ,
 | 
				
			||||||
 | 
					.Fl Fl silent
 | 
				
			||||||
 | 
					.Xc
 | 
				
			||||||
 | 
					Makes
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					do its work silently, unless an error occurs.
 | 
				
			||||||
 | 
					.It Fl t , Fl Fl batch
 | 
				
			||||||
 | 
					Similar to
 | 
				
			||||||
 | 
					.Fl f ,
 | 
				
			||||||
 | 
					in that it suppresses questions, but makes some different assumptions:
 | 
				
			||||||
 | 
					skip patches for which a file to patch can't be found (the same as
 | 
				
			||||||
 | 
					.Fl f ) ;
 | 
				
			||||||
 | 
					skip patches for which the file has the wrong version for the
 | 
				
			||||||
 | 
					.Qq Prereq:
 | 
				
			||||||
 | 
					line in the patch;
 | 
				
			||||||
 | 
					and assume that patches are reversed if they look like they are.
 | 
				
			||||||
 | 
					.It Fl u , Fl Fl unified
 | 
				
			||||||
 | 
					Forces
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					to interpret the patch file as a unified context diff (a unidiff).
 | 
				
			||||||
 | 
					.It Xo
 | 
				
			||||||
 | 
					.Fl V Cm t | nil | never ,
 | 
				
			||||||
 | 
					.Fl Fl version-control Cm t | nil | never
 | 
				
			||||||
 | 
					.Xc
 | 
				
			||||||
 | 
					Causes the next argument to be interpreted as a method for creating
 | 
				
			||||||
 | 
					backup file names.
 | 
				
			||||||
 | 
					The type of backups made can also be given in the
 | 
				
			||||||
 | 
					.Ev PATCH_VERSION_CONTROL
 | 
				
			||||||
 | 
					or
 | 
				
			||||||
 | 
					.Ev VERSION_CONTROL
 | 
				
			||||||
 | 
					environment variables, which are overridden by this option.
 | 
				
			||||||
 | 
					The
 | 
				
			||||||
 | 
					.Fl B
 | 
				
			||||||
 | 
					option overrides this option, causing the prefix to always be used for
 | 
				
			||||||
 | 
					making backup file names.
 | 
				
			||||||
 | 
					The values of the
 | 
				
			||||||
 | 
					.Ev PATCH_VERSION_CONTROL
 | 
				
			||||||
 | 
					and
 | 
				
			||||||
 | 
					.Ev VERSION_CONTROL
 | 
				
			||||||
 | 
					environment variables and the argument to the
 | 
				
			||||||
 | 
					.Fl V
 | 
				
			||||||
 | 
					option are like the GNU Emacs
 | 
				
			||||||
 | 
					.Dq version-control
 | 
				
			||||||
 | 
					variable; they also recognize synonyms that are more descriptive.
 | 
				
			||||||
 | 
					The valid values are (unique abbreviations are accepted):
 | 
				
			||||||
 | 
					.Bl -tag -width Ds -offset indent
 | 
				
			||||||
 | 
					.It Cm t , numbered
 | 
				
			||||||
 | 
					Always make numbered backups.
 | 
				
			||||||
 | 
					.It Cm nil , existing
 | 
				
			||||||
 | 
					Make numbered backups of files that already have them,
 | 
				
			||||||
 | 
					simple backups of the others.
 | 
				
			||||||
 | 
					.It Cm never , simple
 | 
				
			||||||
 | 
					Always make simple backups.
 | 
				
			||||||
 | 
					.El
 | 
				
			||||||
 | 
					.It Fl v , Fl Fl version
 | 
				
			||||||
 | 
					Causes
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					to print out its revision header and patch level.
 | 
				
			||||||
 | 
					.It Xo
 | 
				
			||||||
 | 
					.Fl x Ar number ,
 | 
				
			||||||
 | 
					.Fl Fl debug Ar number
 | 
				
			||||||
 | 
					.Xc
 | 
				
			||||||
 | 
					Sets internal debugging flags, and is of interest only to
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					patchers.
 | 
				
			||||||
 | 
					.It Xo
 | 
				
			||||||
 | 
					.Fl z Ar backup-ext ,
 | 
				
			||||||
 | 
					.Fl Fl suffix Ar backup-ext
 | 
				
			||||||
 | 
					.Xc
 | 
				
			||||||
 | 
					Causes the next argument to be interpreted as the backup extension, to be
 | 
				
			||||||
 | 
					used in place of
 | 
				
			||||||
 | 
					.Qq .orig .
 | 
				
			||||||
 | 
					.It Fl Fl posix
 | 
				
			||||||
 | 
					Enables strict
 | 
				
			||||||
 | 
					.St -p1003.1-2004
 | 
				
			||||||
 | 
					conformance, specifically:
 | 
				
			||||||
 | 
					.Bl -enum
 | 
				
			||||||
 | 
					.It
 | 
				
			||||||
 | 
					Backup files are not created unless the
 | 
				
			||||||
 | 
					.Fl b
 | 
				
			||||||
 | 
					option is specified.
 | 
				
			||||||
 | 
					.It
 | 
				
			||||||
 | 
					If unspecified, the file name used is the first of the old, new and
 | 
				
			||||||
 | 
					index files that exists.
 | 
				
			||||||
 | 
					.El
 | 
				
			||||||
 | 
					.El
 | 
				
			||||||
 | 
					.Ss Patch Application
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					will try to skip any leading garbage, apply the diff,
 | 
				
			||||||
 | 
					and then skip any trailing garbage.
 | 
				
			||||||
 | 
					Thus you could feed an article or message containing a
 | 
				
			||||||
 | 
					diff listing to
 | 
				
			||||||
 | 
					.Nm ,
 | 
				
			||||||
 | 
					and it should work.
 | 
				
			||||||
 | 
					If the entire diff is indented by a consistent amount,
 | 
				
			||||||
 | 
					this will be taken into account.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					With context diffs, and to a lesser extent with normal diffs,
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					can detect when the line numbers mentioned in the patch are incorrect,
 | 
				
			||||||
 | 
					and will attempt to find the correct place to apply each hunk of the patch.
 | 
				
			||||||
 | 
					As a first guess, it takes the line number mentioned for the hunk, plus or
 | 
				
			||||||
 | 
					minus any offset used in applying the previous hunk.
 | 
				
			||||||
 | 
					If that is not the correct place,
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					will scan both forwards and backwards for a set of lines matching the context
 | 
				
			||||||
 | 
					given in the hunk.
 | 
				
			||||||
 | 
					First
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					looks for a place where all lines of the context match.
 | 
				
			||||||
 | 
					If no such place is found, and it's a context diff, and the maximum fuzz factor
 | 
				
			||||||
 | 
					is set to 1 or more, then another scan takes place ignoring the first and last
 | 
				
			||||||
 | 
					line of context.
 | 
				
			||||||
 | 
					If that fails, and the maximum fuzz factor is set to 2 or more,
 | 
				
			||||||
 | 
					the first two and last two lines of context are ignored,
 | 
				
			||||||
 | 
					and another scan is made.
 | 
				
			||||||
 | 
					.Pq The default maximum fuzz factor is 2.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					If
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					cannot find a place to install that hunk of the patch, it will put the hunk
 | 
				
			||||||
 | 
					out to a reject file, which normally is the name of the output file plus
 | 
				
			||||||
 | 
					.Qq .rej .
 | 
				
			||||||
 | 
					(Note that the rejected hunk will come out in context diff form whether the
 | 
				
			||||||
 | 
					input patch was a context diff or a normal diff.
 | 
				
			||||||
 | 
					If the input was a normal diff, many of the contexts will simply be null.)
 | 
				
			||||||
 | 
					The line numbers on the hunks in the reject file may be different than
 | 
				
			||||||
 | 
					in the patch file: they reflect the approximate location patch thinks the
 | 
				
			||||||
 | 
					failed hunks belong in the new file rather than the old one.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					As each hunk is completed, you will be told whether the hunk succeeded or
 | 
				
			||||||
 | 
					failed, and which line (in the new file)
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					thought the hunk should go on.
 | 
				
			||||||
 | 
					If this is different from the line number specified in the diff,
 | 
				
			||||||
 | 
					you will be told the offset.
 | 
				
			||||||
 | 
					A single large offset MAY be an indication that a hunk was installed in the
 | 
				
			||||||
 | 
					wrong place.
 | 
				
			||||||
 | 
					You will also be told if a fuzz factor was used to make the match, in which
 | 
				
			||||||
 | 
					case you should also be slightly suspicious.
 | 
				
			||||||
 | 
					.Ss Filename Determination
 | 
				
			||||||
 | 
					If no original file is specified on the command line,
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					will try to figure out from the leading garbage what the name of the file
 | 
				
			||||||
 | 
					to edit is.
 | 
				
			||||||
 | 
					When checking a prospective file name, pathname components are stripped
 | 
				
			||||||
 | 
					as specified by the
 | 
				
			||||||
 | 
					.Fl p
 | 
				
			||||||
 | 
					option and the file's existence and writability are checked relative
 | 
				
			||||||
 | 
					to the current working directory (or the directory specified by the
 | 
				
			||||||
 | 
					.Fl d
 | 
				
			||||||
 | 
					option).
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					If the diff is a context or unified diff,
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					is able to determine the old and new file names from the diff header.
 | 
				
			||||||
 | 
					For context diffs, the
 | 
				
			||||||
 | 
					.Dq old
 | 
				
			||||||
 | 
					file is specified in the line beginning with
 | 
				
			||||||
 | 
					.Qq ***
 | 
				
			||||||
 | 
					and the
 | 
				
			||||||
 | 
					.Dq new
 | 
				
			||||||
 | 
					file is specified in the line beginning with
 | 
				
			||||||
 | 
					.Qq --- .
 | 
				
			||||||
 | 
					For a unified diff, the
 | 
				
			||||||
 | 
					.Dq old
 | 
				
			||||||
 | 
					file is specified in the line beginning with
 | 
				
			||||||
 | 
					.Qq ---
 | 
				
			||||||
 | 
					and the
 | 
				
			||||||
 | 
					.Dq new
 | 
				
			||||||
 | 
					file is specified in the line beginning with
 | 
				
			||||||
 | 
					.Qq +++ .
 | 
				
			||||||
 | 
					If there is an
 | 
				
			||||||
 | 
					.Qq Index:
 | 
				
			||||||
 | 
					line in the leading garbage (regardless of the diff type),
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					will use the file name from that line as the
 | 
				
			||||||
 | 
					.Dq index
 | 
				
			||||||
 | 
					file.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					will choose the file name by performing the following steps, with the first
 | 
				
			||||||
 | 
					match used:
 | 
				
			||||||
 | 
					.Bl -enum
 | 
				
			||||||
 | 
					.It
 | 
				
			||||||
 | 
					If
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					is operating in strict
 | 
				
			||||||
 | 
					.St -p1003.1-2004
 | 
				
			||||||
 | 
					mode, the first of the
 | 
				
			||||||
 | 
					.Dq old ,
 | 
				
			||||||
 | 
					.Dq new
 | 
				
			||||||
 | 
					and
 | 
				
			||||||
 | 
					.Dq index
 | 
				
			||||||
 | 
					file names that exist is used.
 | 
				
			||||||
 | 
					Otherwise,
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					will examine either the
 | 
				
			||||||
 | 
					.Dq old
 | 
				
			||||||
 | 
					and
 | 
				
			||||||
 | 
					.Dq new
 | 
				
			||||||
 | 
					file names or, for a non-context diff, the
 | 
				
			||||||
 | 
					.Dq index
 | 
				
			||||||
 | 
					file name, and choose the file name with the fewest path components,
 | 
				
			||||||
 | 
					the shortest basename, and the shortest total file name length (in that order).
 | 
				
			||||||
 | 
					.It
 | 
				
			||||||
 | 
					If no file exists,
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					checks for the existence of the files in an SCCS or RCS directory
 | 
				
			||||||
 | 
					(using the appropriate prefix or suffix) using the criteria specified
 | 
				
			||||||
 | 
					above.
 | 
				
			||||||
 | 
					If found,
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					will attempt to get or check out the file.
 | 
				
			||||||
 | 
					.It
 | 
				
			||||||
 | 
					If no suitable file was found to patch, the patch file is a context or
 | 
				
			||||||
 | 
					unified diff, and the old file was zero length, the new file name is
 | 
				
			||||||
 | 
					created and used.
 | 
				
			||||||
 | 
					.It
 | 
				
			||||||
 | 
					If the file name still cannot be determined,
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					will prompt the user for the file name to use.
 | 
				
			||||||
 | 
					.El
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					Additionally, if the leading garbage contains a
 | 
				
			||||||
 | 
					.Qq Prereq:\ \&
 | 
				
			||||||
 | 
					line,
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					will take the first word from the prerequisites line (normally a version
 | 
				
			||||||
 | 
					number) and check the input file to see if that word can be found.
 | 
				
			||||||
 | 
					If not,
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					will ask for confirmation before proceeding.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					The upshot of all this is that you should be able to say, while in a news
 | 
				
			||||||
 | 
					interface, the following:
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					.Dl | patch -d /usr/src/local/blurfl
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					and patch a file in the blurfl directory directly from the article containing
 | 
				
			||||||
 | 
					the patch.
 | 
				
			||||||
 | 
					.Ss Backup Files
 | 
				
			||||||
 | 
					By default, the patched version is put in place of the original, with
 | 
				
			||||||
 | 
					the original file backed up to the same name with the extension
 | 
				
			||||||
 | 
					.Qq .orig ,
 | 
				
			||||||
 | 
					or as specified by the
 | 
				
			||||||
 | 
					.Fl B ,
 | 
				
			||||||
 | 
					.Fl V ,
 | 
				
			||||||
 | 
					or
 | 
				
			||||||
 | 
					.Fl z
 | 
				
			||||||
 | 
					options.
 | 
				
			||||||
 | 
					The extension used for making backup files may also be specified in the
 | 
				
			||||||
 | 
					.Ev SIMPLE_BACKUP_SUFFIX
 | 
				
			||||||
 | 
					environment variable, which is overridden by the options above.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					If the backup file is a symbolic or hard link to the original file,
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					creates a new backup file name by changing the first lowercase letter
 | 
				
			||||||
 | 
					in the last component of the file's name into uppercase.
 | 
				
			||||||
 | 
					If there are no more lowercase letters in the name,
 | 
				
			||||||
 | 
					it removes the first character from the name.
 | 
				
			||||||
 | 
					It repeats this process until it comes up with a
 | 
				
			||||||
 | 
					backup file that does not already exist or is not linked to the original file.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					You may also specify where you want the output to go with the
 | 
				
			||||||
 | 
					.Fl o
 | 
				
			||||||
 | 
					option; if that file already exists, it is backed up first.
 | 
				
			||||||
 | 
					.Ss Notes For Patch Senders
 | 
				
			||||||
 | 
					There are several things you should bear in mind if you are going to
 | 
				
			||||||
 | 
					be sending out patches:
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					First, you can save people a lot of grief by keeping a
 | 
				
			||||||
 | 
					.Pa patchlevel.h
 | 
				
			||||||
 | 
					file which is patched to increment the patch level as the first diff in the
 | 
				
			||||||
 | 
					patch file you send out.
 | 
				
			||||||
 | 
					If you put a
 | 
				
			||||||
 | 
					.Qq Prereq:
 | 
				
			||||||
 | 
					line in with the patch, it won't let them apply
 | 
				
			||||||
 | 
					patches out of order without some warning.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					Second, make sure you've specified the file names right, either in a
 | 
				
			||||||
 | 
					context diff header, or with an
 | 
				
			||||||
 | 
					.Qq Index:
 | 
				
			||||||
 | 
					line.
 | 
				
			||||||
 | 
					If you are patching something in a subdirectory, be sure to tell the patch
 | 
				
			||||||
 | 
					user to specify a
 | 
				
			||||||
 | 
					.Fl p
 | 
				
			||||||
 | 
					option as needed.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					Third, you can create a file by sending out a diff that compares a
 | 
				
			||||||
 | 
					null file to the file you want to create.
 | 
				
			||||||
 | 
					This will only work if the file you want to create doesn't exist already in
 | 
				
			||||||
 | 
					the target directory.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					Fourth, take care not to send out reversed patches, since it makes people wonder
 | 
				
			||||||
 | 
					whether they already applied the patch.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					Fifth, while you may be able to get away with putting 582 diff listings into
 | 
				
			||||||
 | 
					one file, it is probably wiser to group related patches into separate files in
 | 
				
			||||||
 | 
					case something goes haywire.
 | 
				
			||||||
 | 
					.Sh ENVIRONMENT
 | 
				
			||||||
 | 
					.Bl -tag -width "PATCH_VERSION_CONTROL" -compact
 | 
				
			||||||
 | 
					.It Ev POSIXLY_CORRECT
 | 
				
			||||||
 | 
					When set,
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					behaves as if the
 | 
				
			||||||
 | 
					.Fl Fl posix
 | 
				
			||||||
 | 
					option has been specified.
 | 
				
			||||||
 | 
					.It Ev SIMPLE_BACKUP_SUFFIX
 | 
				
			||||||
 | 
					Extension to use for backup file names instead of
 | 
				
			||||||
 | 
					.Qq .orig .
 | 
				
			||||||
 | 
					.It Ev TMPDIR
 | 
				
			||||||
 | 
					Directory to put temporary files in; default is
 | 
				
			||||||
 | 
					.Pa /tmp .
 | 
				
			||||||
 | 
					.It Ev PATCH_VERSION_CONTROL
 | 
				
			||||||
 | 
					Selects when numbered backup files are made.
 | 
				
			||||||
 | 
					.It Ev VERSION_CONTROL
 | 
				
			||||||
 | 
					Same as
 | 
				
			||||||
 | 
					.Ev PATCH_VERSION_CONTROL .
 | 
				
			||||||
 | 
					.El
 | 
				
			||||||
 | 
					.Sh FILES
 | 
				
			||||||
 | 
					.Bl -tag -width "$TMPDIR/patch*" -compact
 | 
				
			||||||
 | 
					.It Pa $TMPDIR/patch*
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					temporary files
 | 
				
			||||||
 | 
					.It Pa /dev/tty
 | 
				
			||||||
 | 
					used to read input when
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					prompts the user
 | 
				
			||||||
 | 
					.El
 | 
				
			||||||
 | 
					.Sh DIAGNOSTICS
 | 
				
			||||||
 | 
					Too many to list here, but generally indicative that
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					couldn't parse your patch file.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					The message
 | 
				
			||||||
 | 
					.Qq Hmm...
 | 
				
			||||||
 | 
					indicates that there is unprocessed text in the patch file and that
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					is attempting to intuit whether there is a patch in that text and, if so,
 | 
				
			||||||
 | 
					what kind of patch it is.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					The
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					utility exits with one of the following values:
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					.Bl -tag -width Ds -compact -offset indent
 | 
				
			||||||
 | 
					.It \&0
 | 
				
			||||||
 | 
					Successful completion.
 | 
				
			||||||
 | 
					.It \&1
 | 
				
			||||||
 | 
					One or more lines were written to a reject file.
 | 
				
			||||||
 | 
					.It \*[Gt]\&1
 | 
				
			||||||
 | 
					An error occurred.
 | 
				
			||||||
 | 
					.El
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					When applying a set of patches in a loop it behooves you to check this
 | 
				
			||||||
 | 
					exit status so you don't apply a later patch to a partially patched file.
 | 
				
			||||||
 | 
					.Sh SEE ALSO
 | 
				
			||||||
 | 
					.Xr diff 1
 | 
				
			||||||
 | 
					.Sh STANDARDS
 | 
				
			||||||
 | 
					The
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					utility is compliant with the
 | 
				
			||||||
 | 
					.St -p1003.1-2004
 | 
				
			||||||
 | 
					specification
 | 
				
			||||||
 | 
					(except as detailed above for the
 | 
				
			||||||
 | 
					.Fl -posix
 | 
				
			||||||
 | 
					option),
 | 
				
			||||||
 | 
					though the presence of
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					itself is optional.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					The flags
 | 
				
			||||||
 | 
					.Op Fl CEfstuvBFVxz
 | 
				
			||||||
 | 
					and
 | 
				
			||||||
 | 
					.Op Fl -posix
 | 
				
			||||||
 | 
					are extensions to that specification.
 | 
				
			||||||
 | 
					.Sh AUTHORS
 | 
				
			||||||
 | 
					.An Larry Wall
 | 
				
			||||||
 | 
					with many other contributors.
 | 
				
			||||||
 | 
					.Sh CAVEATS
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					cannot tell if the line numbers are off in an ed script, and can only detect
 | 
				
			||||||
 | 
					bad line numbers in a normal diff when it finds a
 | 
				
			||||||
 | 
					.Qq change
 | 
				
			||||||
 | 
					or a
 | 
				
			||||||
 | 
					.Qq delete
 | 
				
			||||||
 | 
					command.
 | 
				
			||||||
 | 
					A context diff using fuzz factor 3 may have the same problem.
 | 
				
			||||||
 | 
					Until a suitable interactive interface is added, you should probably do
 | 
				
			||||||
 | 
					a context diff in these cases to see if the changes made sense.
 | 
				
			||||||
 | 
					Of course, compiling without errors is a pretty good indication that the patch
 | 
				
			||||||
 | 
					worked, but not always.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					usually produces the correct results, even when it has to do a lot of
 | 
				
			||||||
 | 
					guessing.
 | 
				
			||||||
 | 
					However, the results are guaranteed to be correct only when the patch is
 | 
				
			||||||
 | 
					applied to exactly the same version of the file that the patch was
 | 
				
			||||||
 | 
					generated from.
 | 
				
			||||||
 | 
					.Sh BUGS
 | 
				
			||||||
 | 
					Could be smarter about partial matches, excessively deviant offsets and
 | 
				
			||||||
 | 
					swapped code, but that would take an extra pass.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					Check patch mode
 | 
				
			||||||
 | 
					.Pq Fl C
 | 
				
			||||||
 | 
					will fail if you try to check several patches in succession that build on
 | 
				
			||||||
 | 
					each other.
 | 
				
			||||||
 | 
					The entire
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					code would have to be restructured to keep temporary files around so that it
 | 
				
			||||||
 | 
					can handle this situation.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					If code has been duplicated (for instance with #ifdef OLDCODE ... #else ...
 | 
				
			||||||
 | 
					#endif),
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					is incapable of patching both versions, and, if it works at all, will likely
 | 
				
			||||||
 | 
					patch the wrong one, and tell you that it succeeded to boot.
 | 
				
			||||||
 | 
					.Pp
 | 
				
			||||||
 | 
					If you apply a patch you've already applied,
 | 
				
			||||||
 | 
					.Nm
 | 
				
			||||||
 | 
					will think it is a reversed patch, and offer to un-apply the patch.
 | 
				
			||||||
 | 
					This could be construed as a feature.
 | 
				
			||||||
							
								
								
									
										1064
									
								
								commands/patch/patch.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1064
									
								
								commands/patch/patch.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										14
									
								
								commands/patch/pathnames.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								commands/patch/pathnames.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * $OpenBSD: pathnames.h,v 1.1 2003/07/29 20:10:17 millert Exp $
 | 
				
			||||||
 | 
					 * $DragonFly: src/usr.bin/patch/pathnames.h,v 1.2 2008/08/11 00:04:12 joerg Exp $
 | 
				
			||||||
 | 
					 * $NetBSD: pathnames.h,v 1.1 2008/09/19 18:33:34 joerg Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Placed in the public domain by Todd C. Miller <Todd.Miller@courtesan.com>
 | 
				
			||||||
 | 
					 * on July 29, 2003.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <paths.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define	_PATH_ED		"/bin/ed"
 | 
				
			||||||
							
								
								
									
										1555
									
								
								commands/patch/pch.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1555
									
								
								commands/patch/pch.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										59
									
								
								commands/patch/pch.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								commands/patch/pch.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * $OpenBSD: pch.h,v 1.9 2003/10/31 20:20:45 millert Exp $
 | 
				
			||||||
 | 
					 * $DragonFly: src/usr.bin/patch/pch.h,v 1.1 2004/09/24 18:44:28 joerg Exp $
 | 
				
			||||||
 | 
					 * $NetBSD: pch.h,v 1.10 2008/09/19 18:33:34 joerg Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * patch - a program to apply diffs to original files
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Copyright 1986, Larry Wall
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					 * modification, are permitted provided that the following condition is met:
 | 
				
			||||||
 | 
					 * 1. Redistributions of source code must retain the above copyright notice,
 | 
				
			||||||
 | 
					 * this condition and the following disclaimer.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
 | 
				
			||||||
 | 
					 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
				
			||||||
 | 
					 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
				
			||||||
 | 
					 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
				
			||||||
 | 
					 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
				
			||||||
 | 
					 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
				
			||||||
 | 
					 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
				
			||||||
 | 
					 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
				
			||||||
 | 
					 * SUCH DAMAGE.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * -C option added in 1998, original code by Marc Espie, based on FreeBSD
 | 
				
			||||||
 | 
					 * behaviour
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define OLD_FILE	0
 | 
				
			||||||
 | 
					#define NEW_FILE	1
 | 
				
			||||||
 | 
					#define INDEX_FILE	2
 | 
				
			||||||
 | 
					#define MAX_FILE	3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct file_name {
 | 
				
			||||||
 | 
						char *path;
 | 
				
			||||||
 | 
						bool exists;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void		re_patch(void);
 | 
				
			||||||
 | 
					void		open_patch_file(const char *);
 | 
				
			||||||
 | 
					void		set_hunkmax(void);
 | 
				
			||||||
 | 
					bool		there_is_another_patch(void);
 | 
				
			||||||
 | 
					bool		another_hunk(void);
 | 
				
			||||||
 | 
					bool		pch_swap(void);
 | 
				
			||||||
 | 
					char		*pfetch(LINENUM);
 | 
				
			||||||
 | 
					short		pch_line_len(LINENUM);
 | 
				
			||||||
 | 
					LINENUM		pch_first(void);
 | 
				
			||||||
 | 
					LINENUM		pch_ptrn_lines(void);
 | 
				
			||||||
 | 
					LINENUM		pch_newfirst(void);
 | 
				
			||||||
 | 
					LINENUM		pch_repl_lines(void);
 | 
				
			||||||
 | 
					LINENUM		pch_end(void);
 | 
				
			||||||
 | 
					LINENUM		pch_context(void);
 | 
				
			||||||
 | 
					LINENUM		pch_hunk_beg(void);
 | 
				
			||||||
 | 
					char		pch_char(LINENUM);
 | 
				
			||||||
 | 
					void		do_ed_script(void);
 | 
				
			||||||
							
								
								
									
										436
									
								
								commands/patch/util.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										436
									
								
								commands/patch/util.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,436 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * $OpenBSD: util.c,v 1.32 2006/03/11 19:41:30 otto Exp $
 | 
				
			||||||
 | 
					 * $DragonFly: src/usr.bin/patch/util.c,v 1.9 2007/09/29 23:11:10 swildner Exp $
 | 
				
			||||||
 | 
					 * $NetBSD: util.c,v 1.24 2008/09/19 18:33:34 joerg Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * patch - a program to apply diffs to original files
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Copyright 1986, Larry Wall
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					 * modification, are permitted provided that the following condition is met:
 | 
				
			||||||
 | 
					 * 1. Redistributions of source code must retain the above copyright notice,
 | 
				
			||||||
 | 
					 * this condition and the following disclaimer.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
 | 
				
			||||||
 | 
					 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
				
			||||||
 | 
					 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
				
			||||||
 | 
					 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
				
			||||||
 | 
					 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
				
			||||||
 | 
					 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
				
			||||||
 | 
					 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
				
			||||||
 | 
					 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
				
			||||||
 | 
					 * SUCH DAMAGE.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * -C option added in 1998, original code by Marc Espie, based on FreeBSD
 | 
				
			||||||
 | 
					 * behaviour
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sys/cdefs.h>
 | 
				
			||||||
 | 
					__RCSID("$NetBSD: util.c,v 1.24 2008/09/19 18:33:34 joerg Exp $");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sys/param.h>
 | 
				
			||||||
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <libgen.h>
 | 
				
			||||||
 | 
					#include <paths.h>
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
 | 
					#include <stdarg.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "common.h"
 | 
				
			||||||
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					#include "backupfile.h"
 | 
				
			||||||
 | 
					#include "pathnames.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Rename a file, copying it if necessary. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					move_file(const char *from, const char *to)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int	fromfd;
 | 
				
			||||||
 | 
						ssize_t	i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* to stdout? */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strEQ(to, "-")) {
 | 
				
			||||||
 | 
					#ifdef DEBUGGING
 | 
				
			||||||
 | 
							if (debug & 4)
 | 
				
			||||||
 | 
								say("Moving %s to stdout.\n", from);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							fromfd = open(from, O_RDONLY);
 | 
				
			||||||
 | 
							if (fromfd < 0)
 | 
				
			||||||
 | 
								pfatal("internal error, can't reopen %s", from);
 | 
				
			||||||
 | 
							while ((i = read(fromfd, buf, buf_len)) > 0)
 | 
				
			||||||
 | 
								if (write(STDOUT_FILENO, buf, i) != i)
 | 
				
			||||||
 | 
									pfatal("write failed");
 | 
				
			||||||
 | 
							close(fromfd);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (backup_file(to) < 0) {
 | 
				
			||||||
 | 
							say("Can't backup %s, output is in %s: %s\n", to, from,
 | 
				
			||||||
 | 
							    strerror(errno));
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#ifdef DEBUGGING
 | 
				
			||||||
 | 
						if (debug & 4)
 | 
				
			||||||
 | 
							say("Moving %s to %s.\n", from, to);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						if (rename(from, to) < 0) {
 | 
				
			||||||
 | 
							if (errno != EXDEV || copy_file(from, to) < 0) {
 | 
				
			||||||
 | 
								say("Can't create %s, output is in %s: %s\n",
 | 
				
			||||||
 | 
								    to, from, strerror(errno));
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Backup the original file.  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					backup_file(const char *orig)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct stat	filestat;
 | 
				
			||||||
 | 
						char		bakname[MAXPATHLEN], *s, *simplename;
 | 
				
			||||||
 | 
						dev_t		orig_device;
 | 
				
			||||||
 | 
						ino_t		orig_inode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (backup_type == none || stat(orig, &filestat) != 0)
 | 
				
			||||||
 | 
							return 0;			/* nothing to do */
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * If the user used zero prefixes or suffixes, then
 | 
				
			||||||
 | 
						 * he doesn't want backups.  Yet we have to remove
 | 
				
			||||||
 | 
						 * orig to break possible hardlinks.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if ((origprae && *origprae == 0) || *simple_backup_suffix == 0) {
 | 
				
			||||||
 | 
							unlink(orig);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						orig_device = filestat.st_dev;
 | 
				
			||||||
 | 
						orig_inode = filestat.st_ino;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (origprae) {
 | 
				
			||||||
 | 
							if (strlcpy(bakname, origprae, sizeof(bakname)) >= sizeof(bakname) ||
 | 
				
			||||||
 | 
							    strlcat(bakname, orig, sizeof(bakname)) >= sizeof(bakname))
 | 
				
			||||||
 | 
								fatal("filename %s too long for buffer\n", origprae);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if ((s = find_backup_file_name(orig)) == NULL)
 | 
				
			||||||
 | 
								fatal("out of memory\n");
 | 
				
			||||||
 | 
							if (strlcpy(bakname, s, sizeof(bakname)) >= sizeof(bakname))
 | 
				
			||||||
 | 
								fatal("filename %s too long for buffer\n", s);
 | 
				
			||||||
 | 
							free(s);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((simplename = strrchr(bakname, '/')) != NULL)
 | 
				
			||||||
 | 
							simplename = simplename + 1;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							simplename = bakname;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Find a backup name that is not the same file. Change the
 | 
				
			||||||
 | 
						 * first lowercase char into uppercase; if that isn't
 | 
				
			||||||
 | 
						 * sufficient, chop off the first char and try again.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						while (stat(bakname, &filestat) == 0 &&
 | 
				
			||||||
 | 
						    orig_device == filestat.st_dev && orig_inode == filestat.st_ino) {
 | 
				
			||||||
 | 
							/* Skip initial non-lowercase chars.  */
 | 
				
			||||||
 | 
							for (s = simplename; *s && !islower((unsigned char)*s); s++)
 | 
				
			||||||
 | 
								;
 | 
				
			||||||
 | 
							if (*s)
 | 
				
			||||||
 | 
								*s = toupper((unsigned char)*s);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								memmove(simplename, simplename + 1,
 | 
				
			||||||
 | 
								    strlen(simplename + 1) + 1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#ifdef DEBUGGING
 | 
				
			||||||
 | 
						if (debug & 4)
 | 
				
			||||||
 | 
							say("Moving %s to %s.\n", orig, bakname);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						if (rename(orig, bakname) < 0) {
 | 
				
			||||||
 | 
							if (errno != EXDEV || copy_file(orig, bakname) < 0)
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copy a file.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					copy_file(const char *from, const char *to)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int	tofd, fromfd;
 | 
				
			||||||
 | 
						ssize_t	i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tofd = open(to, O_CREAT|O_TRUNC|O_WRONLY, 0666);
 | 
				
			||||||
 | 
						if (tofd < 0)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						fromfd = open(from, O_RDONLY, 0);
 | 
				
			||||||
 | 
						if (fromfd < 0)
 | 
				
			||||||
 | 
							pfatal("internal error, can't reopen %s", from);
 | 
				
			||||||
 | 
						while ((i = read(fromfd, buf, buf_len)) > 0)
 | 
				
			||||||
 | 
							if (write(tofd, buf, i) != i)
 | 
				
			||||||
 | 
								pfatal("write to %s failed", to);
 | 
				
			||||||
 | 
						close(fromfd);
 | 
				
			||||||
 | 
						close(tofd);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Allocate a unique area for a string.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					char *
 | 
				
			||||||
 | 
					savestr(const char *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char	*rv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!s)
 | 
				
			||||||
 | 
							s = "Oops";
 | 
				
			||||||
 | 
						rv = strdup(s);
 | 
				
			||||||
 | 
						if (rv == NULL) {
 | 
				
			||||||
 | 
							if (using_plan_a)
 | 
				
			||||||
 | 
								out_of_mem = true;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								fatal("out of memory\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return rv;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Vanilla terminal output (buffered).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					say(const char *fmt, ...)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						va_list	ap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						va_start(ap, fmt);
 | 
				
			||||||
 | 
						vfprintf(stderr, fmt, ap);
 | 
				
			||||||
 | 
						va_end(ap);
 | 
				
			||||||
 | 
						fflush(stderr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Terminal output, pun intended.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					fatal(const char *fmt, ...)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						va_list	ap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						va_start(ap, fmt);
 | 
				
			||||||
 | 
						fprintf(stderr, "patch: **** ");
 | 
				
			||||||
 | 
						vfprintf(stderr, fmt, ap);
 | 
				
			||||||
 | 
						va_end(ap);
 | 
				
			||||||
 | 
						my_exit(2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Say something from patch, something from the system, then silence . . .
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					pfatal(const char *fmt, ...)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						va_list	ap;
 | 
				
			||||||
 | 
						int	errnum = errno;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fprintf(stderr, "patch: **** ");
 | 
				
			||||||
 | 
						va_start(ap, fmt);
 | 
				
			||||||
 | 
						vfprintf(stderr, fmt, ap);
 | 
				
			||||||
 | 
						va_end(ap);
 | 
				
			||||||
 | 
						fprintf(stderr, ": %s\n", strerror(errnum));
 | 
				
			||||||
 | 
						my_exit(2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Get a response from the user via /dev/tty
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					ask(const char *fmt, ...)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						va_list	ap;
 | 
				
			||||||
 | 
						ssize_t	nr = 0;
 | 
				
			||||||
 | 
						static	int ttyfd = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						va_start(ap, fmt);
 | 
				
			||||||
 | 
						vfprintf(stdout, fmt, ap);
 | 
				
			||||||
 | 
						va_end(ap);
 | 
				
			||||||
 | 
						fflush(stdout);
 | 
				
			||||||
 | 
						if (ttyfd < 0)
 | 
				
			||||||
 | 
							ttyfd = open(_PATH_TTY, O_RDONLY);
 | 
				
			||||||
 | 
						if (ttyfd >= 0) {
 | 
				
			||||||
 | 
							if ((nr = read(ttyfd, buf, buf_len)) > 0 &&
 | 
				
			||||||
 | 
							    buf[nr - 1] == '\n')
 | 
				
			||||||
 | 
								buf[nr - 1] = '\0';
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ttyfd < 0 || nr <= 0) {
 | 
				
			||||||
 | 
							/* no tty or error reading, pretend user entered 'return' */
 | 
				
			||||||
 | 
							putchar('\n');
 | 
				
			||||||
 | 
							buf[0] = '\0';
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * How to handle certain events when not in a critical region.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					set_signals(int reset)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static sig_t	hupval, intval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!reset) {
 | 
				
			||||||
 | 
							hupval = signal(SIGHUP, SIG_IGN);
 | 
				
			||||||
 | 
							if (hupval != SIG_IGN)
 | 
				
			||||||
 | 
								hupval = my_exit;
 | 
				
			||||||
 | 
							intval = signal(SIGINT, SIG_IGN);
 | 
				
			||||||
 | 
							if (intval != SIG_IGN)
 | 
				
			||||||
 | 
								intval = my_exit;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						signal(SIGHUP, hupval);
 | 
				
			||||||
 | 
						signal(SIGINT, intval);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * How to handle certain events when in a critical region.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					ignore_signals(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						signal(SIGHUP, SIG_IGN);
 | 
				
			||||||
 | 
						signal(SIGINT, SIG_IGN);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Make sure we'll have the directories to create a file. If `striplast' is
 | 
				
			||||||
 | 
					 * true, ignore the last element of `filename'.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					makedirs(const char *filename, bool striplast)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char	*tmpbuf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((tmpbuf = strdup(filename)) == NULL)
 | 
				
			||||||
 | 
							fatal("out of memory\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (striplast) {
 | 
				
			||||||
 | 
							char	*s = strrchr(tmpbuf, '/');
 | 
				
			||||||
 | 
							if (s == NULL)
 | 
				
			||||||
 | 
								return;	/* nothing to be done */
 | 
				
			||||||
 | 
							*s = '\0';
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (mkpath(tmpbuf) != 0)
 | 
				
			||||||
 | 
							pfatal("creation of %s failed", tmpbuf);
 | 
				
			||||||
 | 
						free(tmpbuf);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Make filenames more reasonable.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					char *
 | 
				
			||||||
 | 
					fetchname(const char *at, bool *exists, int strip_leading)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char		*fullname, *name, *t;
 | 
				
			||||||
 | 
						int		sleading, tab;
 | 
				
			||||||
 | 
						struct stat	filestat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (at == NULL || *at == '\0')
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						while (isspace((unsigned char)*at))
 | 
				
			||||||
 | 
							at++;
 | 
				
			||||||
 | 
					#ifdef DEBUGGING
 | 
				
			||||||
 | 
						if (debug & 128)
 | 
				
			||||||
 | 
							say("fetchname %s %d\n", at, strip_leading);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						/* So files can be created by diffing against /dev/null.  */
 | 
				
			||||||
 | 
						if (strnEQ(at, _PATH_DEVNULL, sizeof(_PATH_DEVNULL) - 1))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						name = fullname = t = savestr(at);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tab = strchr(t, '\t') != NULL;
 | 
				
			||||||
 | 
						/* Strip off up to `strip_leading' path components and NUL terminate. */
 | 
				
			||||||
 | 
						for (sleading = strip_leading; *t != '\0' && ((tab && *t != '\t') ||
 | 
				
			||||||
 | 
						    !isspace((unsigned char)*t)); t++) {
 | 
				
			||||||
 | 
							if (t[0] == '/' && t[1] != '/' && t[1] != '\0')
 | 
				
			||||||
 | 
								if (--sleading >= 0)
 | 
				
			||||||
 | 
									name = t + 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						*t = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * If no -p option was given (957 is the default value!), we were
 | 
				
			||||||
 | 
						 * given a relative pathname, and the leading directories that we
 | 
				
			||||||
 | 
						 * just stripped off all exist, put them back on.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (strip_leading == 957 && name != fullname && *fullname != '/') {
 | 
				
			||||||
 | 
							name[-1] = '\0';
 | 
				
			||||||
 | 
							if (stat(fullname, &filestat) == 0 && S_ISDIR(filestat.st_mode)) {
 | 
				
			||||||
 | 
								name[-1] = '/';
 | 
				
			||||||
 | 
								name = fullname;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						name = savestr(name);
 | 
				
			||||||
 | 
						free(fullname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*exists = stat(name, &filestat) == 0;
 | 
				
			||||||
 | 
						return name;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Takes the name returned by fetchname and looks in RCS/SCCS directories
 | 
				
			||||||
 | 
					 * for a checked in version.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					char *
 | 
				
			||||||
 | 
					checked_in(char *file)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char		*filebase, *filedir, tmpbuf[MAXPATHLEN];
 | 
				
			||||||
 | 
						struct stat	filestat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						filebase = basename(file);
 | 
				
			||||||
 | 
						filedir = dirname(file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define try(f, a1, a2, a3) \
 | 
				
			||||||
 | 
					(snprintf(tmpbuf, sizeof tmpbuf, f, a1, a2, a3), stat(tmpbuf, &filestat) == 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX) ||
 | 
				
			||||||
 | 
						    try("%s/RCS/%s%s", filedir, filebase, "") ||
 | 
				
			||||||
 | 
						    try("%s/%s%s", filedir, filebase, RCSSUFFIX) ||
 | 
				
			||||||
 | 
						    try("%s/SCCS/%s%s", filedir, SCCSPREFIX, filebase) ||
 | 
				
			||||||
 | 
						    try("%s/%s%s", filedir, SCCSPREFIX, filebase))
 | 
				
			||||||
 | 
							return file;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					version(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						fprintf(stderr, "Patch version 2.0-12u8-NetBSD\n");
 | 
				
			||||||
 | 
						my_exit(EXIT_SUCCESS);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Exit with cleanup.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					my_exit(int status)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unlink(TMPINNAME);
 | 
				
			||||||
 | 
						if (!toutkeep)
 | 
				
			||||||
 | 
							unlink(TMPOUTNAME);
 | 
				
			||||||
 | 
						if (!trejkeep)
 | 
				
			||||||
 | 
							unlink(TMPREJNAME);
 | 
				
			||||||
 | 
						unlink(TMPPATNAME);
 | 
				
			||||||
 | 
						exit(status);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										54
									
								
								commands/patch/util.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								commands/patch/util.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,54 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * $OpenBSD: util.h,v 1.15 2005/06/20 07:14:06 otto Exp $
 | 
				
			||||||
 | 
					 * $DragonFly: src/usr.bin/patch/util.h,v 1.2 2007/09/29 23:11:10 swildner Exp $
 | 
				
			||||||
 | 
					 * $NetBSD: util.h,v 1.11 2008/09/19 18:33:34 joerg Exp $
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * patch - a program to apply diffs to original files
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Copyright 1986, Larry Wall
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					 * modification, are permitted provided that the following condition is met:
 | 
				
			||||||
 | 
					 * 1. Redistributions of source code must retain the above copyright notice,
 | 
				
			||||||
 | 
					 * this condition and the following disclaimer.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
 | 
				
			||||||
 | 
					 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
				
			||||||
 | 
					 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
				
			||||||
 | 
					 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
				
			||||||
 | 
					 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
				
			||||||
 | 
					 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
				
			||||||
 | 
					 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
				
			||||||
 | 
					 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
				
			||||||
 | 
					 * SUCH DAMAGE.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * -C option added in 1998, original code by Marc Espie, based on FreeBSD
 | 
				
			||||||
 | 
					 * behaviour
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char		*fetchname(const char *, bool *, int);
 | 
				
			||||||
 | 
					char		*checked_in(char *);
 | 
				
			||||||
 | 
					int		backup_file(const char *);
 | 
				
			||||||
 | 
					int		move_file(const char *, const char *);
 | 
				
			||||||
 | 
					int		copy_file(const char *, const char *);
 | 
				
			||||||
 | 
					void		say(const char *, ...)
 | 
				
			||||||
 | 
							    __attribute__((__format__(__printf__, 1, 2)));
 | 
				
			||||||
 | 
					void		fatal(const char *, ...)
 | 
				
			||||||
 | 
							    __attribute__((__format__(__printf__, 1, 2)));
 | 
				
			||||||
 | 
					void		pfatal(const char *, ...)
 | 
				
			||||||
 | 
							    __attribute__((__format__(__printf__, 1, 2)));
 | 
				
			||||||
 | 
					void		ask(const char *, ...)
 | 
				
			||||||
 | 
							    __attribute__((__format__(__printf__, 1, 2)));
 | 
				
			||||||
 | 
					char		*savestr(const char *);
 | 
				
			||||||
 | 
					void		set_signals(int);
 | 
				
			||||||
 | 
					void		ignore_signals(void);
 | 
				
			||||||
 | 
					void		makedirs(const char *, bool);
 | 
				
			||||||
 | 
					void		version(void);
 | 
				
			||||||
 | 
					void		my_exit(int) __attribute__((noreturn));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* in mkpath.c */
 | 
				
			||||||
 | 
					extern int mkpath(char *);
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user