9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

main.c (4447B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <bio.h>
      4 #include "diff.h"
      5 
      6 #define	DIRECTORY(s)		((s)->qid.type&QTDIR)
      7 #define	REGULAR_FILE(s)		((s)->type == 'M' && !DIRECTORY(s))
      8 
      9 Biobuf	stdout;
     10 
     11 static char *tmp[] = {"/tmp/diff1XXXXXXXXXXX", "/tmp/diff2XXXXXXXXXXX"};
     12 static int whichtmp;
     13 static char *progname;
     14 static char usage[] = "diff [ -acefmnbwr ] file1 ... file2\n";
     15 
     16 static void
     17 rmtmpfiles(void)
     18 {
     19 	while (whichtmp > 0) {
     20 		whichtmp--;
     21 		remove(tmp[whichtmp]);
     22 	}
     23 }
     24 
     25 void	
     26 done(int status)
     27 {
     28 	rmtmpfiles();
     29 	switch(status)
     30 	{
     31 	case 0:
     32 		exits("");
     33 	case 1:
     34 		exits("some");
     35 	default:
     36 		exits("error");
     37 	}
     38 	/*NOTREACHED*/
     39 }
     40 
     41 void
     42 panic(int status, char *fmt, ...)
     43 {
     44 	va_list arg;
     45 
     46 	Bflush(&stdout);
     47 
     48 	fprint(2, "%s: ", progname);
     49 	va_start(arg, fmt);
     50 	vfprint(2, fmt, arg);
     51 	va_end(arg);
     52 	if (status)
     53 		done(status);
     54 		/*NOTREACHED*/
     55 }
     56 
     57 static int
     58 catch(void *a, char *msg)
     59 {
     60 	USED(a);
     61 	panic(2, msg);
     62 	return 1;
     63 }
     64 
     65 int
     66 mkpathname(char *pathname, char *path, char *name)
     67 {
     68 	if (strlen(path) + strlen(name) > MAXPATHLEN) {
     69 		panic(0, "pathname %s/%s too long\n", path, name);
     70 		return 1;
     71 	}
     72 	sprint(pathname, "%s/%s", path, name);
     73 	return 0;
     74 }
     75 	
     76 static char *
     77 mktmpfile(int input, Dir **sb)
     78 {
     79 	int fd, i;
     80 	char *p;
     81 	char buf[8192];
     82 
     83 	atnotify(catch, 1);
     84 /*
     85 	p = mktemp(tmp[whichtmp++]);
     86 	fd = create(p, OWRITE, 0600);
     87 */
     88 	fd = mkstemp(p=tmp[whichtmp++]);
     89 	if (fd < 0) {
     90 		panic(mflag ? 0: 2, "cannot create %s: %r\n", p);
     91 		return 0;
     92 	}
     93 	while ((i = read(input, buf, sizeof(buf))) > 0) {
     94 		if ((i = write(fd, buf, i)) < 0)
     95 			break;
     96 	}
     97 	*sb = dirfstat(fd);
     98 	close(fd);
     99 	if (i < 0) {
    100 		panic(mflag ? 0: 2, "cannot read/write %s: %r\n", p);
    101 		return 0;
    102 	}
    103 	return p;
    104 }
    105 
    106 static char *
    107 statfile(char *file, Dir **sb)
    108 {
    109 	Dir *dir;
    110 	int input;
    111 
    112 	dir = dirstat(file);
    113 	if(dir == nil) {
    114 		if (strcmp(file, "-") || (dir = dirfstat(0)) == nil) {
    115 			panic(mflag ? 0: 2, "cannot stat %s: %r\n", file);
    116 			return 0;
    117 		}
    118 		free(dir);
    119 		return mktmpfile(0, sb);
    120 	}
    121 	else if (!REGULAR_FILE(dir) && !DIRECTORY(dir)) {
    122 		free(dir);
    123 		if ((input = open(file, OREAD)) == -1) {
    124 			panic(mflag ? 0: 2, "cannot open %s: %r\n", file);
    125 			return 0;
    126 		}
    127 		file = mktmpfile(input, sb);
    128 		close(input);
    129 	}
    130 	else
    131 		*sb = dir;
    132 	return file;
    133 }
    134 
    135 void
    136 diff(char *f, char *t, int level)
    137 {
    138 	char *fp, *tp, *p, fb[MAXPATHLEN+1], tb[MAXPATHLEN+1];
    139 	Dir *fsb, *tsb;
    140 
    141 	if ((fp = statfile(f, &fsb)) == 0)
    142 		goto Return;
    143 	if ((tp = statfile(t, &tsb)) == 0){
    144 		free(fsb);
    145 		goto Return;
    146 	}
    147 	if (DIRECTORY(fsb) && DIRECTORY(tsb)) {
    148 		if (rflag || level == 0)
    149 			diffdir(fp, tp, level);
    150 		else
    151 			Bprint(&stdout, "Common subdirectories: %s and %s\n",
    152 				fp, tp);
    153 	}
    154 	else if (REGULAR_FILE(fsb) && REGULAR_FILE(tsb))
    155 		diffreg(fp, tp);
    156 	else {
    157 		if (REGULAR_FILE(fsb)) {
    158 			if ((p = utfrrune(f, '/')) == 0)
    159 				p = f;
    160 			else
    161 				p++;
    162 			if (mkpathname(tb, tp, p) == 0)
    163 				diffreg(fp, tb);
    164 		}
    165 		else {
    166 			if ((p = utfrrune(t, '/')) == 0)
    167 				p = t;
    168 			else
    169 				p++;
    170 			if (mkpathname(fb, fp, p) == 0)
    171 				diffreg(fb, tp);
    172 		}
    173 	}
    174 	free(fsb);
    175 	free(tsb);
    176 Return:
    177 	rmtmpfiles();
    178 }
    179 
    180 void
    181 main(int argc, char *argv[])
    182 {
    183 	char *p;
    184 	int i;
    185 	Dir *fsb, *tsb;
    186 	extern int _p9usepwlibrary;
    187 	
    188 	_p9usepwlibrary = 0;
    189 	Binit(&stdout, 1, OWRITE);
    190 	progname = *argv;
    191 	while (--argc && (*++argv)[0] == '-' && (*argv)[1]) {
    192 		for (p = *argv+1; *p; p++) {
    193 			switch (*p) {
    194 
    195 			case 'e':
    196 			case 'f':
    197 			case 'n':
    198 			case 'c':
    199 			case 'a':
    200 				mode = *p;
    201 				break;
    202 
    203 			case 'w':
    204 				bflag = 2;
    205 				break;
    206 
    207 			case 'b':
    208 				bflag = 1;
    209 				break;
    210 
    211 			case 'r':
    212 				rflag = 1;
    213 				mflag = 1;
    214 				break;
    215 
    216 			case 'm':
    217 				mflag = 1;	
    218 				break;
    219 
    220 			case 'h':
    221 			default:
    222 				progname = "Usage";
    223 				panic(2, usage);
    224 			}
    225 		}
    226 	}
    227 	if (argc < 2)
    228 		panic(2, usage, progname);
    229 	if ((tsb = dirstat(argv[argc-1])) == nil)
    230 		panic(2, "can't stat %s\n", argv[argc-1]);
    231 	if (argc > 2) {
    232 		if (!DIRECTORY(tsb))
    233 			panic(2, usage, progname);
    234 		mflag = 1;
    235 	}
    236 	else {
    237 		if ((fsb = dirstat(argv[0])) == nil)
    238 			panic(2, "can't stat %s\n", argv[0]);
    239 		if (DIRECTORY(fsb) && DIRECTORY(tsb))
    240 			mflag = 1;
    241 		free(fsb);
    242 	}
    243 	free(tsb);
    244 	for (i = 0; i < argc-1; i++)
    245 		diff(argv[i], argv[argc-1], 0);
    246 	done(anychange);
    247 	/*NOTREACHED*/
    248 }
    249 
    250 static char noroom[] = "out of memory - try diff -h\n";
    251 
    252 void *
    253 emalloc(unsigned n)
    254 {
    255 	register void *p;
    256 
    257 	if ((p = malloc(n)) == 0)
    258 		panic(2, noroom);
    259 	return p;
    260 }
    261 
    262 void *
    263 erealloc(void *p, unsigned n)
    264 {
    265 	register void *rp;
    266 
    267 	if ((rp = realloc(p, n)) == 0)
    268 		panic(2, noroom);
    269 	return rp;
    270 }