#!/usr/bin/env bx use b Main() if args != 3 usage("from-dir to-dir diff-dir") cstr from = arg[0] cstr to = arg[1] cstr diff = arg[2] cstr dir_1 = path_cat(diff, "1") cstr dir_2 = path_cat(diff, "2") cstr dir_3 = path_cat(diff, "3") Mkdir_if(diff) Mkdir_if(dir_1) Mkdir_if(dir_2) Mkdir_if(dir_3) new(from_v, vec, cstr, 1024) new(to_v, vec, cstr, 1024) cstr basedir = Getcwd() Chdir(from) find_vec_all(".", from_v) Chdir(basedir) Chdir(to) find_vec_all(".", to_v) Chdir(basedir) sort_vec(from_v, cstrp_cmp) sort_vec(to_v, cstrp_cmp) int size = vec_get_size(from_v) + vec_get_size(to_v) new(comm_v, vec, byte, size) new(merge_v, vec, cstr, size) comm_vecs(merge_v, comm_v, from_v, to_v, cstrp_cmp, NULL) # NULL -> don't free unused objects, will free from_v and to_v later write_output(merge_v, comm_v, from, to, dir_1, dir_2, dir_3) write_output(vec *merge_v, vec *comm_v, cstr from, cstr to, cstr dir_1, cstr dir_2, cstr dir_3) cstr dir[4] = { NULL, dir_1, dir_2, dir_3 } assert(vec_get_size(comm_v) == vec_get_size(merge_v), "badcall: write_output %d %d", vec_get_size(comm_v), vec_get_size(merge_v)) vec_null_terminate(merge_v) cstr *m = vec_get_start(merge_v) byte *c = vec_get_start(comm_v) while *m warn("%d\t%s", *c, *m) cstr o = path_cat(dir[*c], *m) cstr f = NULL cstr t = NULL decl(sf, lstats) decl(st, lstats) if *c & 1 f = path_cat(from, *m) init(sf, lstats, f) if *c & 2 t = path_cat(to, *m) init(st, lstats, t) which *c 1 if S_ISDIR(sf->st_mode) Mkdirs(o) else CP(f, o, sf) st = sf 2 if S_ISDIR(st->st_mode) Mkdirs(o) else CP(t, o, st) 3 if S_ISREG(sf->st_mode) && S_ISREG(st->st_mode) Systeml("bsdiff", f, t, o, NULL) break if S_ISDIR(sf->st_mode) && S_ISDIR(st->st_mode) Mkdirs(o) cstr o1 = path_cat(dir[1], *m) cstr o2 = path_cat(dir[2], *m) if S_ISDIR(sf->st_mode) Mkdirs(o1) else CP(f, o1, sf) cp_attrs(st, o1) if S_ISDIR(st->st_mode) Mkdirs(o2) else CP(t, o2, sf) cp_attrs(st, o2) Free(o1) Free(o2) if Exists(o) cp_attrs(st, o) ++m ; ++c Free(o) Free(f) Free(t)