123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572 |
- #include "libbb.h"
- struct double_list {
- struct double_list *next;
- struct double_list *prev;
- char *data;
- };
- static void dlist_free(struct double_list *list, void (*freeit)(void *data))
- {
- while (list) {
- void *pop = list;
- list = list->next;
- freeit(pop);
-
- if (list == pop) break;
- }
- }
- static struct double_list *dlist_add(struct double_list **list, char *data)
- {
- struct double_list *llist;
- struct double_list *line = xmalloc(sizeof(*line));
- line->data = data;
- llist = *list;
- if (llist) {
- struct double_list *p;
- line->next = llist;
- p = line->prev = llist->prev;
-
- p->next = line;
- llist->prev = line;
- } else
- *list = line->next = line->prev = line;
- return line;
- }
- struct globals {
- char *infile;
- long prefix;
- struct double_list *current_hunk;
- long oldline, oldlen, newline, newlen;
- long linenum;
- int context, state, hunknum;
- int filein, fileout;
- char *tempname;
- int exitval;
- };
- #define TT (*ptr_to_globals)
- #define INIT_TT() do { \
- SET_PTR_TO_GLOBALS(xzalloc(sizeof(TT))); \
- } while (0)
- #define FLAG_STR "Rup:i:NEx"
- #define FLAG_REVERSE (1 << 0)
- #define FLAG_u (1 << 1)
- #define FLAG_PATHLEN (1 << 2)
- #define FLAG_INPUT (1 << 3)
- #define FLAG_IGNORE (1 << 4)
- #define FLAG_RMEMPTY (1 << 5)
- #define FLAG_DEBUG (0 << 6)
- #define PATCH_DEBUG (option_mask32 & FLAG_DEBUG)
- static void do_line(void *data)
- {
- struct double_list *dlist = data;
- if (TT.state>1 && *dlist->data != TT.state)
- fdprintf(TT.state == 2 ? 2 : TT.fileout,
- "%s\n", dlist->data+(TT.state>3 ? 1 : 0));
- if (PATCH_DEBUG) fdprintf(2, "DO %d: %s\n", TT.state, dlist->data);
- free(dlist->data);
- free(dlist);
- }
- static void finish_oldfile(void)
- {
- if (TT.tempname) {
-
- char *temp;
- if (TT.filein != -1) {
- bb_copyfd_eof(TT.filein, TT.fileout);
- xclose(TT.filein);
- }
- xclose(TT.fileout);
- temp = xstrdup(TT.tempname);
- temp[strlen(temp) - 6] = '\0';
- rename(TT.tempname, temp);
- free(temp);
- free(TT.tempname);
- TT.tempname = NULL;
- }
- TT.fileout = TT.filein = -1;
- }
- static void fail_hunk(void)
- {
- if (!TT.current_hunk) return;
- fdprintf(2, "Hunk %d FAILED %ld/%ld.\n", TT.hunknum, TT.oldline, TT.newline);
- TT.exitval = 1;
-
-
- TT.state = 2;
- TT.current_hunk->prev->next = NULL;
- dlist_free(TT.current_hunk, do_line);
- TT.current_hunk = NULL;
-
- close(TT.filein);
- close(TT.fileout);
- unlink(TT.tempname);
- free(TT.tempname);
- TT.tempname = NULL;
- TT.state = 0;
- }
- static int apply_one_hunk(void)
- {
- struct double_list *plist, *buf = NULL, *check;
- int matcheof = 0, reverse = option_mask32 & FLAG_REVERSE, backwarn = 0;
-
- int dummy_revert = 0;
-
- TT.current_hunk->prev->next = NULL;
-
- for (plist = TT.current_hunk; plist; plist = plist->next) {
- if (plist->data[0]==' ') matcheof++;
- else matcheof = 0;
- if (PATCH_DEBUG) fdprintf(2, "HUNK:%s\n", plist->data);
- }
- matcheof = !matcheof || matcheof < TT.context;
- if (PATCH_DEBUG) fdprintf(2,"MATCHEOF=%c\n", matcheof ? 'Y' : 'N');
-
-
-
- plist = TT.current_hunk;
- buf = NULL;
- if (reverse ? TT.oldlen : TT.newlen) for (;;) {
- char *data = xmalloc_reads(TT.filein, NULL);
- TT.linenum++;
-
-
- while (plist && *plist->data == "+-"[reverse]) {
- if (data && strcmp(data, plist->data+1) == 0) {
- if (!backwarn) {
- backwarn = TT.linenum;
- if (option_mask32 & FLAG_IGNORE) {
- dummy_revert = 1;
- reverse ^= 1;
- continue;
- }
- }
- }
- plist = plist->next;
- }
-
- if (!data) {
- if (PATCH_DEBUG) fdprintf(2, "INEOF\n");
-
- if (!plist && matcheof) break;
- if (backwarn)
- fdprintf(2,"Possibly reversed hunk %d at %ld\n",
- TT.hunknum, TT.linenum);
-
- fail_hunk();
- goto done;
- }
- if (PATCH_DEBUG) fdprintf(2, "IN: %s\n", data);
- check = dlist_add(&buf, data);
-
-
-
-
-
-
-
- for (;;) {
- while (plist && *plist->data == "+-"[reverse]) {
- if (strcmp(check->data, plist->data+1) == 0
- && !backwarn
- ) {
- backwarn = TT.linenum;
- if (option_mask32 & FLAG_IGNORE) {
- dummy_revert = 1;
- reverse ^= 1;
- }
- }
- plist = plist->next;
- }
- if (!plist || strcmp(check->data, plist->data+1)) {
-
-
- if (PATCH_DEBUG)
- fdprintf(2, "NOT: %s\n", plist ? plist->data : "EOF");
- TT.state = 3;
- check = buf;
- buf = buf->next;
- check->prev->next = buf;
- buf->prev = check->prev;
- do_line(check);
- plist = TT.current_hunk;
-
-
- if (check == buf) {
- buf = NULL;
- break;
- }
- check = buf;
- } else {
- if (PATCH_DEBUG)
- fdprintf(2, "MAYBE: %s\n", plist->data);
-
- plist = plist->next;
- if (!plist && !matcheof) goto out;
- check = check->next;
- if (check == buf) break;
- }
- }
- }
- out:
-
- TT.state = "-+"[reverse ^ dummy_revert];
- dlist_free(TT.current_hunk, do_line);
- TT.current_hunk = NULL;
- TT.state = 1;
- done:
- if (buf) {
- buf->prev->next = NULL;
- dlist_free(buf, do_line);
- }
- return TT.state;
- }
- int patch_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
- int patch_main(int argc UNUSED_PARAM, char **argv)
- {
- int opts;
- int reverse, state = 0;
- char *oldname = NULL, *newname = NULL;
- char *opt_p, *opt_i;
- long oldlen = oldlen;
- long newlen = newlen;
- INIT_TT();
- opts = getopt32(argv, FLAG_STR, &opt_p, &opt_i);
- argv += optind;
- reverse = opts & FLAG_REVERSE;
- TT.prefix = (opts & FLAG_PATHLEN) ? xatoi(opt_p) : 0;
- TT.filein = TT.fileout = -1;
- if (opts & FLAG_INPUT) {
- xmove_fd(xopen_stdin(opt_i), STDIN_FILENO);
- } else {
- if (argv[0] && argv[1]) {
- xmove_fd(xopen_stdin(argv[1]), STDIN_FILENO);
- }
- }
-
- for(;;) {
- char *patchline;
- patchline = xmalloc_fgetline(stdin);
- if (!patchline) break;
-
-
- if (!*patchline) {
- free(patchline);
- patchline = xstrdup(" ");
- }
-
- if (state >= 2) {
- if (*patchline==' ' || *patchline=='+' || *patchline=='-') {
- dlist_add(&TT.current_hunk, patchline);
- if (*patchline != '+') oldlen--;
- if (*patchline != '-') newlen--;
-
- if (*patchline==' ' && state==2) TT.context++;
- else state=3;
-
- if (!oldlen && !newlen) state = apply_one_hunk();
- continue;
- }
- fail_hunk();
- state = 0;
- continue;
- }
-
- if (is_prefixed_with(patchline, "--- ") || is_prefixed_with(patchline, "+++ ")) {
- char *s, **name = reverse ? &newname : &oldname;
- int i;
- if (*patchline == '+') {
- name = reverse ? &oldname : &newname;
- state = 1;
- }
- finish_oldfile();
- if (!argv[0]) {
- free(*name);
-
- for (s = patchline+4; *s && *s!='\t'; s++)
- if (*s=='\\' && s[1]) s++;
- i = atoi(s);
- if (i>1900 && i<=1970)
- *name = xstrdup("/dev/null");
- else {
- *s = 0;
- *name = xstrdup(patchline+4);
- }
- }
-
-
-
-
-
-
- } else if (state == 1 && is_prefixed_with(patchline, "@@ -")) {
- int i;
- char *s = patchline+4;
-
- TT.oldlen = oldlen = TT.newlen = newlen = 1;
- TT.oldline = strtol(s, &s, 10);
- if (*s == ',') TT.oldlen = oldlen = strtol(s+1, &s, 10);
- TT.newline = strtol(s+2, &s, 10);
- if (*s == ',') TT.newlen = newlen = strtol(s+1, &s, 10);
- if (oldlen < 1 && newlen < 1)
- bb_error_msg_and_die("Really? %s", patchline);
- TT.context = 0;
- state = 2;
-
-
-
- if (!oldname)
- oldname = xstrdup("MISSING_FILENAME");
- if (!newname)
- newname = xstrdup("MISSING_FILENAME");
-
- if (TT.filein == -1) {
- int oldsum, newsum, empty = 0;
- char *name;
- oldsum = TT.oldline + oldlen;
- newsum = TT.newline + newlen;
- name = reverse ? oldname : newname;
-
-
- if (strcmp(name, "/dev/null") == 0 || !(reverse ? oldsum : newsum)) {
- name = reverse ? newname : oldname;
- empty = 1;
- }
-
- for (i = 0, s = name; *s;) {
- if ((option_mask32 & FLAG_PATHLEN) && TT.prefix == i)
- break;
- if (*s++ != '/')
- continue;
- while (*s == '/')
- s++;
- i++;
- name = s;
- }
-
- if (argv[0])
- name = argv[0];
- if (empty) {
-
- state = 0;
- if (option_mask32 & FLAG_RMEMPTY) {
-
- printf("removing %s\n", name);
- xunlink(name);
- } else {
- printf("patching file %s\n", name);
- xclose(xopen(name, O_WRONLY | O_TRUNC));
- }
-
- } else if (!(option_mask32 & FLAG_PATHLEN) || i <= TT.prefix) {
- struct stat statbuf;
-
- if (strcmp(oldname, "/dev/null") == 0 || !oldsum) {
- printf("creating %s\n", name);
- s = strrchr(name, '/');
- if (s) {
- *s = 0;
- bb_make_directory(name, -1, FILEUTILS_RECUR);
- *s = '/';
- }
- TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR);
- } else {
- printf("patching file %s\n", name);
- TT.filein = xopen(name, O_RDONLY);
- }
- TT.tempname = xasprintf("%sXXXXXX", name);
- TT.fileout = xmkstemp(TT.tempname);
-
- fstat(TT.filein, &statbuf);
- fchmod(TT.fileout, statbuf.st_mode);
- TT.linenum = 0;
- TT.hunknum = 0;
- }
- }
- TT.hunknum++;
- continue;
- }
-
- free(patchline);
- }
- finish_oldfile();
- if (ENABLE_FEATURE_CLEAN_UP) {
- free(oldname);
- free(newname);
- }
- return TT.exitval;
- }
|