/* * Something a bit like git-add -i, except not depending on perl, and * partially crossed with git-commit. * * Usage: $0 [file [file ...]] * * Runs git diff with the same arguments. Any non-text diffs cause an * immediate error out. Text diffs are accumulated; each diff hunk is * remembered separately. The user interface allows the user to, * repeatedly, choose from: * * - Quit. * - Commit what's staged (by running git-commit). * - Choose a diff hunk to be included. * - Stage the files corresponding to the chosen hunks. * - Show diffs from HEAD to the index. */ #include #include #include #include #include #include "fatal.h" #include "subproc.h" #include "memstream.h" #include static void initial_git_diff(int ac, char **av) { int newac; const char **newav; int ofd; int efd; MEMSTREAM *om; MEMSTREAM *em; struct pollfd pfd[2]; int px; int opx; int epx; int rv; char rbuf[8192]; newac = ac; newav = malloc((newac+1)*sizeof(char *)); newav[0] = "git-diff"; bcopy(av+1,newav+1,(ac-1)*sizeof(char *)); newav[newac] = 0; fork_child(newav,0,&ofd,&efd); om = memstream_open_w(); em = memstream_open_w(); while (1) { px = 0; if (ofd >= 0) { opx = px; pfd[px++] = (struct pollfd) { .fd = ofd, .events = POLLIN | POLLRDNORM }; } else { opx = -1; } if (efd >= 0) { epx = px; pfd[px++] = (struct pollfd) { .fd = efd, .events = POLLIN | POLLRDNORM }; } else { epx = -1; } if (px == 0) break; rv = poll(&pfd[0],px,INFTIM); if (rv < 0) { if (errno == EINTR) continue; fatal("poll: %s",strerror(errno)); } if ((opx >= 0) && (pfd[opx].revents & (POLLIN|POLLRDNORM))) { rv = read(ofd,&rbuf[0],sizeof(rbuf)); if (rv < 0) { switch (errno) { case EINTR: case EWOULDBLOCK: break; default: fatal("pipe read: %s",strerror(errno)); break; } } else if (rv == 0) { close(ofd); ofd = -1; } else { memstream_append(om,&rbuf[0],rv); } } if ((epx >= 0) && (pfd[epx].revents & (POLLIN|POLLRDNORM))) { rv = read(efd,&rbuf[0],sizeof(rbuf)); if (rv < 0) { switch (errno) { case EINTR: case EWOULDBLOCK: break; default: fatal("pipe read: %s",strerror(errno)); break; } } else if (rv == 0) { close(efd); efd = -1; } else { memstream_append(em,&rbuf[0],rv); } } } { void chunk(const void *data, int len) { fwrite(data,1,len,stdout); } printf("stdout:\n\n"); memstream_dump(om,&chunk); printf("\n\nstderr:\n\n"); memstream_dump(em,&chunk); printf("\n"); } } int main(int, char **); int main(int ac, char **av) { initial_git_diff(ac,av); return(0); }