⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 diff.c

📁 操作系统源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* diff  - print differences between 2 files	  Author: Erik Baalbergen *//* Poor man's implementation of diff(1) 	- no options available* 	- may give more output than other diffs,*	  due to the straight-forward algorithm* 	- runs out of memory if the differing chunks become too large* 	- input line length should not exceed LINELEN; longer lines are*	  truncated, while only the first LINELEN characters are compared** 	- Bug fixes by Rick Thomas Sept. 1989** Please report bugs and suggestions to erikb@cs.vu.nl*------------------------------------------------------------------------------* Changed diff to conform to POSIX 1003.2 ( Draft 11) by Thomas Brupbacher* ( tobr@mw.lpc.ethz.ch).** To incorporate the context diff option -c in the program, the source code* for the program cdiff has been copied to the end of this program. Only* slight modifications for the cdiff code to work within the program diff* were made( e.g. main() -> context_diff()).** New options:* -c, -C n where n=0,1,...:*  	produces a context diff as the program cdiff. The default is to*  	print 3 lines of context, this value can be changed with -C*	( e.g. -C 5 prints five lines of context.)* -e :	Prints an ed script, so you can convert <file1> to <file2> with*  	the command ed <file1> < `diff -e <file1> <file2>`.* -b :	Causes trailing blanks to be ignored and spaces of multiple blanks*  	to be reduced to one blank before comparison.*-----------------------------------------------------------------------------*/#include <stdlib.h>#include <limits.h>		/* NAME_MAX for maximal filename length	 */#include <string.h>		/* string manipulation			 */#include <sys/types.h>#include <sys/stat.h>#include <sys/wait.h>#include <ctype.h>#include <time.h>#include <dirent.h>#include <unistd.h>#include <stdio.h>/* These definitions are needed only to suppress warning messages. */#define Nullfp 		((FILE*)0)#define Nullch 		((char*)0)#define NullStructLine	((struct line *)0)#define LINELEN 128		/* max line length included in diff	 */#define NOT_SET 0		/* Defines to characterise if a flag 	 */#define SET	1		/* is set				 */ /* Indexes of the warning-message array	 */#define EXCLUSIVE_OPTIONS	0#define CANNOT_OPEN_FILE	1 /* Used to define the mode 		 */typedef enum {  undefined, context, ed_mode} MODE; /* Global variables for the 'normal' diff part	 */char *progname;			/* program name	(on command line)	 */int diffs = 0;			/* number of differences		 */MODE mode;			/* which mode is used			 */int severe_error;		/* nonzero after severe, non-fatal error *//* The following global variables are used with the -r option: * for every pair of files that are different, a "command line" of the * form "diff <options> <oldfile> <newfile>" is printed before the real * output starts.							 */int firstoutput = 1;		/* flag to print one time		 */char options_string[10];	/* string to hold command line options 	 */char oldfile[PATH_MAX];		/* first file				 */char newfile[PATH_MAX];		/* second file				 */ /* Global variables for the command-line options */int trim_blanks = NOT_SET;	/* SET if -b specified	 		 */int recursive_dir = NOT_SET;	/* SET if -r specified	 		 */int context_lines = 3;		/* numbers of lines in a context	 */static int offset;		/* offset of the actual line number for -e */ /* Function prototypes for the functions in this file	 */struct f;_PROTOTYPE(int main, (int argc, char **argv ));_PROTOTYPE(void process_command_line, (int argc, char **argv ));_PROTOTYPE(void analyse_input_files, (char *arg1, char *arg2, char *input1, 							char *input2 ));_PROTOTYPE(void diff, (char *filename1, char *filename2 ));_PROTOTYPE(FILE *check_file, (char *name ));_PROTOTYPE(void build_option_string, (void ));_PROTOTYPE(void fatal_error, (char *fmt, char *s ));_PROTOTYPE(void warn, (int number, char *string ));_PROTOTYPE(void trimming_blanks, (char *l_text ));_PROTOTYPE(char *filename, (char *path_string));_PROTOTYPE(struct line *new_line, (int size ));_PROTOTYPE(void free_line, (struct line *l ));_PROTOTYPE(int equal_line, (struct line *l1, struct line *l2 ));_PROTOTYPE(int equal_3, (struct line *l1, struct line *l2 ));_PROTOTYPE(struct line *read_line, (FILE *fp ));_PROTOTYPE(void advance, (struct f *f ));_PROTOTYPE(void aside, (struct f *f, struct line *l ));_PROTOTYPE(struct line *next, (struct f *f ));_PROTOTYPE(void init_f, (struct f *f, FILE *fp ));_PROTOTYPE(void update, (struct f *f, char *s ));_PROTOTYPE(void __diff, (FILE *fp1, FILE *fp2 ));_PROTOTYPE(void differ, (struct f *f1, struct f *f2 ));_PROTOTYPE(int wlen, (struct f *f ));_PROTOTYPE(void range, (int a, int b ));_PROTOTYPE(void cdiff, (char *old, char *new, FILE *file1, FILE *file2 ));_PROTOTYPE(void dumphunk, (void ));_PROTOTYPE(char *getold, (int targ ));_PROTOTYPE(char *getnew, (int targ ));_PROTOTYPE(int isdir, (char *path ));_PROTOTYPE(void diff_recursive, (char *dir1, char *dir2 ));_PROTOTYPE(void file_type_error, (char *filename1, char *filename2, 			struct stat *statbuf1, struct stat *statbuf2 ));_PROTOTYPE(void *xmalloc, (size_t size));_PROTOTYPE(void *xrealloc, (void *ptr, size_t size));int main(argc, argv)int argc;char **argv;{  char file1[PATH_MAX], file2[PATH_MAX];  extern int optind;		/* index of the current string in argv	 */  progname = argv[0];  process_command_line(argc, argv);  analyse_input_files(argv[optind], argv[optind + 1], file1, file2);  optind++;  if (recursive_dir == SET) {	build_option_string();	diff_recursive(file1, file2);  } else {	diff(file1, file2);  }  return(severe_error ? 2 : diffs > 0 ? 1 : 0);}/* Process the command line and set the flags for the different * options. the processing of the command line is done with the * getopt() library function. a minimal error processing is done * for the number of command line arguments.				 */void process_command_line(argc, argv)int argc;			/* number of arguments on command line	 */char **argv;			/* ** to arguments on command line	 */{  int c;  extern char *optarg;		/* points to string with options	 */  extern int optind;		/* index of the current string in argv	 */  /* Are there enough arguments?		 */  if (argc < 3) {	fatal_error("Usage: %s [-c|-e|-C n][-br] file1 file2\n", progname);  }  /* Process all options using getopt()	 */  while ((c = getopt(argc, argv, "ceC:br")) != -1) {	switch (c) {	    case 'c':		if (mode != undefined) warn(EXCLUSIVE_OPTIONS, "c");		mode = context;		context_lines = 3;		break;	    case 'e':		if (mode != undefined) warn(EXCLUSIVE_OPTIONS, "e");		mode = ed_mode;		break;	    case 'C':		if (mode != undefined) warn(EXCLUSIVE_OPTIONS, "C");		mode = context;		context_lines = atoi(optarg);		break;	    case 'b':	trim_blanks = SET;	break;	    case 'r':	recursive_dir = SET;	break;	    case '?':		exit(2);	}  }  /* We should have two arguments left	 */  if ((argc - optind) != 2)	fatal_error("Need exactly two input file-names!\n", "");}/* Analyse_input_files takes the two input files on the command line * and decides what to do. returns the (corrected) filenames that * can be used to call diff(). * if two directories are given, then a recursive diff is done. * one directory and one filename compares the file with <filename> * in the directory <directory> with <filename>. * if two filenames are specified, no special action takes place. */void analyse_input_files(arg1, arg2, input1, input2)char *arg1, *arg2;		/* filenames on the command line	 */char *input1, *input2;		/* filenames to be used with diff()	 */{  int stat1 = 0, stat2 = 0;  if (strcmp(arg1, "-") != 0)	stat1 = isdir(arg1);	/* != 0 <-> arg1 is directory		 */  if (strcmp(arg2, "-") != 0) stat2 = isdir(arg2);#ifdef DEBUG  fprintf(stderr, "%s, stat = %d\n", arg1, stat1);  fprintf(stderr, "%s, stat = %d\n", arg2, stat2);#endif  if (stat1 && stat2) {		/* both arg1 and arg2 are directories */	recursive_dir = SET;	strcpy(input1, arg1);	strcpy(input2, arg2);	return;  }  if (stat1 != 0) {		/* arg1 is a dir, arg2 not		 */	if (strcmp(arg2, "-") != 0) {	/* arg2 != stdin	 */		strcpy(input1, arg1);		strcat(input1, "/");		strcat(input1, arg2);		strcpy(input2, arg2);		return;	} else {		fatal_error("cannot compare stdin (-) with a directory!", "");	}  }  if (stat2 != 0) {		/* arg2 is a dir, arg1 not		 */	if (strcmp(arg1, "-") != 0) {	/* arg1 != stdin	 */		strcpy(input1, arg1);		strcpy(input2, arg2);		strcat(input2, "/");		strcat(input2, arg1);		return;	} else {		/* arg1 == stdin			 */		fatal_error("cannot compare stdin (-) with a directory!", "");	}  }  /* Both arg1 and arg2 are normal  files	 */  strcpy(input1, arg1);  strcpy(input2, arg2);}/* Diff() is the front end for all modes of the program diff, execpt * the recursive_dir option. * diff() expects the filenames of the two files to be compared as * arguments. the mode is determined from the global variable mode. */void diff(filename1, filename2)char *filename1, *filename2;{  FILE *file1 = check_file(filename1);  FILE *file2 = check_file(filename2);  struct stat statbuf1, statbuf2;  if ((file1 != Nullfp) && (file2 != Nullfp)) {	/* If we do a recursive diff, then we don't compare block	 * special, character special or FIFO special files to any	 * file.			  */	fstat(fileno(file1), &statbuf1);	fstat(fileno(file2), &statbuf2);	if ((((statbuf1.st_mode & S_IFREG) != S_IFREG) ||	     ((statbuf2.st_mode & S_IFREG) != S_IFREG)) &&	    (recursive_dir == SET)) {		file_type_error(filename1, filename2, &statbuf1, &statbuf2);	} else {		switch (mode) {		    case context:			cdiff(filename1, filename2, file1, file2);			break;		    case ed_mode:		    case undefined:			__diff(file1, file2);			if (mode == ed_mode) printf("w\n");			break;		}	}  } else	severe_error = 1;  if (file1 != Nullfp) fclose(file1);  if (file2 != Nullfp) fclose(file2);}/* Check_file() opens the fileptr with name <filename>. if <filename> * equals "-" stdin is associated with the return value. */FILE *check_file(name)char *name;{  FILE *temp;  if (strcmp(name, "-") == 0) {	return(stdin);  } else {	temp = fopen(name, "r");	if (temp == Nullfp) warn(CANNOT_OPEN_FILE, name);	return(temp);  }}/* Build_option_string() is called before recursive_dir() is called * from the main() function. its purpose is to build the string that * is used on the command line to get the current operation mode. * e.g. "-C 6 -b". */void build_option_string(){  switch (mode) {	    case ed_mode:sprintf(options_string, "-e");	break;      case context:	if (context_lines == 3)		sprintf(options_string, "-c");	else		sprintf(options_string, "-C %d", context_lines);	break;  }}/* The fatal error handler. * Expects a format string and a string as arguments. The arguments * are printed to stderr and the program exits with an error code 2. */void fatal_error(fmt, s)char *fmt;			/* the format sttring to be printed	 */char *s;			/* string to be inserted into the format				 * string				 */{  fprintf(stderr, "%s: ", progname);  fprintf(stderr, fmt, s);  fprintf(stderr, "\n");  exit(2);}/* This function prints non fatal error messages to stderr. * Expects the index of the message to be printed and a pointer * to the (optional) string to be printed. * Returns no value. */void warn(number, string)int number;			/* index of the warning			 */char *string;			/* string to be inserted to the warning	 */{  static char *warning[] = {    "%s: The options -c, -e, -C n are mutually exclusive! Assuming -%c\n",    "%s: cannot open file %s for reading\n",  };  fprintf(stderr, warning[number], progname, string);}/* Function used with the optione -b, trims the blanks in a input line: * - blanks between words are reduced to one * - trailing blanks are eliminated. */void trimming_blanks(l_text)char *l_text;			/* begin of the char array		 */{  char *line = l_text;  char *copy_to, *copy_from;  do {	if (*line == ' ') {		copy_from = line;		copy_to = line;		while (*(++copy_from) == ' ');		if (*copy_from != '\n') copy_to++;		while (*copy_from != '\0') *(copy_to++) = *(copy_from++);		*copy_to = '\0';	}  } while (*(++line) != '\0');}/* Filename separates the filename and the relative path in path_string. * Returns the filename with a leading / */char *filename(path_string)char *path_string;{  char name[NAME_MAX + 2];	/* filename plus /		 	 */  char *ptr;  name[0] = '/';  ptr = strrchr(path_string, '/');  if (ptr == 0) {		/* no / in path_string, only a filename	 */	strcat(name, path_string);  } else {	strcat(name, ptr);  }  return(name);}/* The line module: one member in a linked list of lines. */struct line {  struct line *l_next;		/* pointer to the next line	 */  char l_eof;			/* == 0 if last line in file	 */  char *l_text;			/* array with the text		 */};struct line *freelist = 0;#define stepup(ll) ( ((ll) && ((ll)->l_eof==0)) ? (ll)->l_next : (ll) )/* Function to allocate space for a new line containing SIZE chars	*/struct line *new_line(size)int size;{  register struct line *l;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -