Files
Arquivotheca.AIX-4.1.3/bos/usr/bin/diff/diff.c
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

433 lines
12 KiB
C

static char sccsid[] = "@(#)46 1.14 src/bos/usr/bin/diff/diff.c, cmdfiles, bos412, 9446C 11/14/94 16:48:14";
/*
* COMPONENT_NAME: (CMDFILES) commands that manipulate files
*
* FUNCTIONS: diff
*
* ORIGINS: 3, 18, 26, 27, 71
*
* This module contains IBM CONFIDENTIAL code. -- (IBM
* Confidential Restricted when combined with the aggregated
* modules for this product)
* SOURCE MATERIALS
* (C) COPYRIGHT International Business Machines Corp. 1985, 1994
* All Rights Reserved
*
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*
*
* (c) Copyright 1990, 1991, 1992 OPEN SOFTWARE FOUNDATION, INC.
* ALL RIGHTS RESERVED
*
*/
#include <stdio.h>
#include <locale.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include "diff.h"
nl_catd catd;
/* Determine whether current locale is SBCS or MBCS for diffdir and diffreg.*/
static int mb_cur_max; /* max number of bytes per character in current locale */
int mbcodeset; /* 0=current locale SBCS, 1=current locale MBCS */
/* Let diffdir and diffreg implement "wclen(wc)" by "wctomb(ignore_mb,wc)" */
char ignore_mb[MB_LEN_MAX];
/*
* Output format options
*/
int opt;
int tflag=0; /* expand tabs on output */
/*
* Algorithm related options
*/
int hflag=0; /* -h, use halfhearted DIFFH */
int bflag=0; /* ignore blanks in comparisons */
int wflag=0; /* totally ignore blanks in comparisons*/
int iflag=0; /* ignore case in comparisons */
/*
* Options on hierarchical diffs.
*/
int lflag=0; /* long output format with header */
int rflag=0; /* recursively trace directories */
int sflag=0; /* announce files which are same */
char *begin = NULL; /* do file only if name >= this */
/*
* Variables for -I D_IFDEF option.
*/
int wantelses; /* -E */
char *def1; /* String for -1 */
char *def2; /* String for -2 */
/*
* Variables for -c context option.
*/
int context; /* lines of context to be printed */
/*
* State for exit status.
*/
int status;
int oldstatus;
char *tempfile; /* used when comparing against std input */
/*
* Variables for diffdir.
*/
char **diffargv; /* option list to pass to recursive diffs */
char *slinkcmpsbuf1; /* Allocate symbolic link buffers outside recursion */
char *slinkcmpsbuf2;
/*
* Input file names.
* With diffdir, file1 and file2 are allocated BUFSIZ space,
* and padded with a '/', and then efile0 and efile1 point after
* the '/'.
*/
char *file1, *file2, *efile1, *efile2;
struct stat stb1, stb2;
/*
* This is allocated early, and used
* to reset the free storage pointer to effect space compaction.
*/
char *dummy;
char *talloc(), *ralloc();
char *savestr();
int done();
/*
* Variable for passing NAME_MAX to diffreg and diffdir
*/
int name_max;
/*
* NAME: diff - driver and subroutines
* FUNCTION: compare two files
* FLAGS:
* Options when comparing directories are:
* -l long output format; each text file diff is piped through pr to
* paginate it, other differences are remembered and summarized
* after all text file differences are reported.
* -r causes application of diff recursively to common subdirectories
* -s casuses diff to report files which are the same, which are
* otherwise not memtioned.
* -Sname starts a directory diff in the middle beginning with file name.
* The following options are mutually exclusive:
* -e produces a script for the command ed
* -f produces a script similar to -e but in the opposite order
* -n produces a script similar to that of -e, but in the opposite
* order and with a count of changed lines on each insert or
* delete command.
* -c produces a diff with lines of context
* -h does a fast, half-hearted job.
* -Dstring cause diff to create a merged version of file1 and file2,
* with C preprocessor controls included.
* Other flags
* -b causes trailing blanks (spaces and tabs) to be ignored, and
* other strings of blanks to compare equal.
* -w causes whitespace (blanks and tabs) to be totally ignored.
* -i ignores the case of letters
* -t will expand tabs in output lines
*/
#ifdef DIFF
char diff[] = DIFF;
#else
char diff[] = "/usr/bin/diff";
#endif
#ifdef DIFFH
char diffh[] = DIFFH;
#else
char diffh[] = "/usr/lbin/diffh";
#endif
#ifdef PR
char pr[] = PR;
#else
char pr[] = "/usr/bin/pr";
#endif
main(argc, argv)
int argc;
char **argv;
{
register char *argp;
extern char *optarg;
extern int optind, optopt, opterr;
int c; /* char for getopt() value */
unsigned char ucc; /* c disguised as char */
unsigned char uco; /* optopt disguised as char */
char **ep;
int badopt;
int mb_cur_max; /* max number of bytes per character in current locale */
(void) setlocale(LC_ALL,"");
catd = catopen(MF_DIFF, NL_CAT_LOCALE);
mb_cur_max = MB_CUR_MAX;
mbcodeset = (mb_cur_max > 1?1:0);
def1 = "FILE1"; def2 = "FILE2";
oldstatus = status = 0;
diffargv = argv;
badopt = 0;
/* Option -c is allowed to have traditional optional argument.
* This version of option handling uses POSIX 1003.2/D10 getopt().
* This version will not work with the 1003.2/D11 version of
* getopt() because missing-argument conventions are different.
*/
opterr = 0;
while ((c = getopt(argc,argv,"bcC:D:efhilnrsS:tw")) != -1) {
ucc = (unsigned char)c;
switch (ucc) {
case 'b':
bflag = 1;
break;
case 'c':
opt = DI_CONTEXT;
context = 3;
break;
case 'C':
/* optarg must point to a positive numeric argument */
ep = &optarg;
if ( optarg != NULL
&& ((context = (int)strtoul(optarg,ep,10)) >= 0)
&& (ep == NULL || *ep == NULL || **ep=='\0')) {
opt = DI_CONTEXT;
} else {
fprintf(stderr,MSGSTR(EBADCNT3,
"diff: -%c: bad count\n"),ucc);
status=2;
badopt++;
}
break;
case 'D':
/* optarg must point to valid -D argument */
wantelses = 1;
def1 = "";
opt = DI_IFDEF;
def2 = optarg;
break;
case 'e':
opt = DI_EDIT;
break;
case 'f':
opt = DI_REVERSE;
break;
case 'h':
hflag = 1;
break;
case 'i':
iflag = 1;
break;
case 'l':
lflag = 1;
break;
case 'n':
opt = DI_NREVERSE;
break;
case 'r':
rflag = 1;
break;
case 's':
sflag = 1;
break;
case 'S':
/* optarg points to -S argument. To disable -S effects below top
* level operands, use empty string optarg as convention for
* recursive call out of diffdir, and ignore -S in that case.
* (Same effect as if user said diff -S "" .)
* Method: remember -S argument here and mark it null in argv[].
* When argv is passed in recursive call (via diffargv) it will
* look like -S "" .
*/
if (strcmp(optarg,"")!= 0) {
begin = strcpy((char *)malloc(strlen(optarg)+2),optarg);
*optarg = '\0';
}
break;
case 't':
tflag = 1;
break;
case 'w':
wflag = 1;
break;
case '?': /* Mimic getopt() error messages where appropriate */
uco = (unsigned char)optopt;
switch (uco) {
case 'D': /* Omitted String in [-D String] : missing argument */
case 'C': /* Omitted Number in [-C Number] : missing argument */
case 'S': /* Omitted File in [-S File] : missing argument */
fprintf(stderr,MSGSTR(EOPTARG,
"diff: option requires an argument -- %c\n"),uco);
status=2;
badopt++;
break;
default: /* Anything else: illegal option */
fprintf(stderr,MSGSTR(EILLOPT,
"diff: illegal option -- %c\n"),uco);
status=2;
badopt++;
break;
} /* switch (uco) */
break;
} /* switch(ucc) */
} /* while ((c = getopt ... */
/* Check for exactly two File or Directory operands
* (allowing for mystery machinations by getopt())
*/
if ((argc - optind) == 2) {
file1 = argv[optind ];
file2 = argv[optind+1];
} else {
fprintf(stderr,MSGSTR(ETWO,
"diff: two filename arguments required\n"));
status=2;
badopt++;
}
if (hflag && opt) {
fprintf(stderr,MSGSTR(EBAD,
"diff: -h doesn't support -e, -f, -n, -c, or -D\n"));
status=2;
badopt++;
}
if (badopt) {
fprintf(stderr,MSGSTR(USAGE,
"Usage: diff [-bcitw] [[-C Lines|-D String|-e|-f|-n]|[-h]] File1 File2\n\
diff [-bcilrstw] [[-C Lines|-e|-f|-n]|[-h]] [-S File] Directory1 Directory2\n"
));
status=2;
exit(status);
}
if (!strcmp(file1, "-"))
stb1.st_mode = S_IFREG;
else if (stat(file1, &stb1) < 0) {
fputs("diff: ",stderr);
perror(file1);
status=2;
done();
}
if (!strcmp(file2, "-"))
stb2.st_mode = S_IFREG;
else if (stat(file2, &stb2) < 0) {
fputs("diff: ",stderr);
perror(file2);
status=2;
done();
}
/* Get NAME_MAX value if at least one operand is a regular file */
if ( ((name_max=pathconf(file1,_PC_NAME_MAX)) == -1)
&& ((name_max=pathconf(file2,_PC_NAME_MAX)) == -1)) {
if ( strcmp(file1,"-")==0 && strcmp(file2,"-")==0)
fprintf(stderr,MSGSTR(DSTDINS,
"diff: can't specify - -\n"));
else
fprintf(stderr,MSGSTR(ENOPATHMAX,
"diff: Cannot get _PC_NAME_MAX.\n"));
status=2;
done();
}
if ((stb1.st_mode & S_IFMT) == S_IFDIR &&
(stb2.st_mode & S_IFMT) == S_IFDIR) {
if ( (slinkcmpsbuf1 = (char *)malloc(name_max+2)) == NULL ||
(slinkcmpsbuf2 = (char *)malloc(name_max+2)) == NULL ) {
fprintf(stderr,MSGSTR(ESLINK,
"diff: Cannot allocate symbolic link space.\n"));
status=2;
done();
};
diffdir(argv);
} else
diffreg();
done();
}
/* save a copy of string cp */
char *
savestr(cp)
register char *cp;
{
register char *dp;
dp = (char *) malloc((size_t)(strlen(cp)+1));
if (dp == 0) {
fprintf(stderr,MSGSTR(EMEM,"diff: ran out of memory\n"));
done();
}
strcpy(dp, cp);
return (dp);
}
/* return the integer with the minimun value */
min(a,b)
int a,b;
{
return (a < b ? a : b);
}
/* return the integer with the maxinum value */
max(a,b)
int a,b;
{
return (a > b ? a : b);
}
/* delete tempfile and exit */
done()
{
unlink(tempfile);
exit(status);
}
/* malloc with test */
char *
talloc(n)
{
register char *p;
p = malloc((size_t)n);
if(p!=NULL)
return(p);
noroom();
}
char *
ralloc(p,n) /*compacting reallocation */
char *p;
{
register char *q;
q = realloc((void *)p, (size_t)n);
if(q==NULL)
noroom();
return(q);
}
/* out of memory, print error message and exit */
static
noroom()
{
fprintf(stderr,MSGSTR(ESIZE,"diff: files too big, try -h\n"));
done();
}