]> git.ipfire.org Git - thirdparty/git.git/blobdiff - sequencer.c
commit-graph.c: ensure graph layers respect core.sharedRepository
[thirdparty/git.git] / sequencer.c
index df6d18f9ab609c1e1e050b509b587495f7957f90..f30bb73c703a2b872dec85de7c68f6aa6c0b075d 100644 (file)
@@ -40,7 +40,7 @@ static const char cherry_picked_prefix[] = "(cherry picked from commit ";
 
 GIT_PATH_FUNC(git_path_commit_editmsg, "COMMIT_EDITMSG")
 
-GIT_PATH_FUNC(git_path_seq_dir, "sequencer")
+static GIT_PATH_FUNC(git_path_seq_dir, "sequencer")
 
 static GIT_PATH_FUNC(git_path_todo_file, "sequencer/todo")
 static GIT_PATH_FUNC(git_path_opts_file, "sequencer/opts")
@@ -57,6 +57,8 @@ static GIT_PATH_FUNC(rebase_path, "rebase-merge")
 GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo")
 GIT_PATH_FUNC(rebase_path_todo_backup, "rebase-merge/git-rebase-todo.backup")
 
+GIT_PATH_FUNC(rebase_path_dropped, "rebase-merge/dropped")
+
 /*
  * The rebase command lines that have already been processed. A line
  * is moved here when it is first handled, before any associated user
@@ -158,6 +160,8 @@ static GIT_PATH_FUNC(rebase_path_strategy, "rebase-merge/strategy")
 static GIT_PATH_FUNC(rebase_path_strategy_opts, "rebase-merge/strategy_opts")
 static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, "rebase-merge/allow_rerere_autoupdate")
 static GIT_PATH_FUNC(rebase_path_reschedule_failed_exec, "rebase-merge/reschedule-failed-exec")
+static GIT_PATH_FUNC(rebase_path_drop_redundant_commits, "rebase-merge/drop_redundant_commits")
+static GIT_PATH_FUNC(rebase_path_keep_redundant_commits, "rebase-merge/keep_redundant_commits")
 
 static int git_sequencer_config(const char *k, const char *v, void *cb)
 {
@@ -288,7 +292,7 @@ int sequencer_remove_state(struct replay_opts *opts)
                        char *eol = strchr(p, '\n');
                        if (eol)
                                *eol = '\0';
-                       if (delete_ref("(rebase -i) cleanup", p, NULL, 0) < 0) {
+                       if (delete_ref("(rebase) cleanup", p, NULL, 0) < 0) {
                                warning(_("could not delete '%s'"), p);
                                ret = -1;
                        }
@@ -322,7 +326,7 @@ static const char *action_name(const struct replay_opts *opts)
        case REPLAY_PICK:
                return N_("cherry-pick");
        case REPLAY_INTERACTIVE_REBASE:
-               return N_("rebase -i");
+               return N_("rebase");
        }
        die(_("unknown action: %d"), opts->action);
 }
@@ -626,7 +630,7 @@ static int do_recursive_merge(struct repository *r,
                               COMMIT_LOCK | SKIP_IF_UNCHANGED))
                /*
                 * TRANSLATORS: %s will be "revert", "cherry-pick" or
-                * "rebase -i".
+                * "rebase".
                 */
                return error(_("%s: Unable to write new index file"),
                        _(action_name(opts)));
@@ -942,6 +946,8 @@ static int run_git_commit(struct repository *r,
                argv_array_push(&cmd.args, "--amend");
        if (opts->gpg_sign)
                argv_array_pushf(&cmd.args, "-S%s", opts->gpg_sign);
+       else
+               argv_array_push(&cmd.args, "--no-gpg-sign");
        if (defmsg)
                argv_array_pushl(&cmd.args, "-F", defmsg, NULL);
        else if (!(flags & EDIT_MSG))
@@ -1319,7 +1325,7 @@ static int try_to_commit(struct repository *r,
                return -1;
 
        if (flags & AMEND_MSG) {
-               const char *exclude_gpgsig[] = { "gpgsig", NULL };
+               const char *exclude_gpgsig[] = { "gpgsig", "gpgsig-sha256", NULL };
                const char *out_enc = get_commit_output_encoding();
                const char *message = logmsg_reencode(current_head, NULL,
                                                      out_enc);
@@ -1429,9 +1435,19 @@ out:
        return res;
 }
 
+static int write_rebase_head(struct object_id *oid)
+{
+       if (update_ref("rebase", "REBASE_HEAD", oid,
+                      NULL, REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
+               return error(_("could not update %s"), "REBASE_HEAD");
+
+       return 0;
+}
+
 static int do_commit(struct repository *r,
                     const char *msg_file, const char *author,
-                    struct replay_opts *opts, unsigned int flags)
+                    struct replay_opts *opts, unsigned int flags,
+                    struct object_id *oid)
 {
        int res = 1;
 
@@ -1456,8 +1472,12 @@ static int do_commit(struct repository *r,
                        return res;
                }
        }
-       if (res == 1)
+       if (res == 1) {
+               if (is_rebase_i(opts) && oid)
+                       if (write_rebase_head(oid))
+                           return -1;
                return run_git_commit(r, msg_file, opts, flags);
+       }
 
        return res;
 }
@@ -1483,23 +1503,30 @@ static int is_original_commit_empty(struct commit *commit)
 }
 
 /*
- * Do we run "git commit" with "--allow-empty"?
+ * Should empty commits be allowed?  Return status:
+ *    <0: Error in is_index_unchanged(r) or is_original_commit_empty(commit)
+ *     0: Halt on empty commit
+ *     1: Allow empty commit
+ *     2: Drop empty commit
  */
 static int allow_empty(struct repository *r,
                       struct replay_opts *opts,
                       struct commit *commit)
 {
-       int index_unchanged, empty_commit;
+       int index_unchanged, originally_empty;
 
        /*
-        * Three cases:
+        * Four cases:
         *
         * (1) we do not allow empty at all and error out.
         *
-        * (2) we allow ones that were initially empty, but
-        * forbid the ones that become empty;
+        * (2) we allow ones that were initially empty, and
+        *     just drop the ones that become empty
         *
-        * (3) we allow both.
+        * (3) we allow ones that were initially empty, but
+        *     halt for the ones that become empty;
+        *
+        * (4) we allow both.
         */
        if (!opts->allow_empty)
                return 0; /* let "git commit" barf as necessary */
@@ -1513,13 +1540,15 @@ static int allow_empty(struct repository *r,
        if (opts->keep_redundant_commits)
                return 1;
 
-       empty_commit = is_original_commit_empty(commit);
-       if (empty_commit < 0)
-               return empty_commit;
-       if (!empty_commit)
-               return 0;
-       else
+       originally_empty = is_original_commit_empty(commit);
+       if (originally_empty < 0)
+               return originally_empty;
+       if (originally_empty)
                return 1;
+       else if (opts->drop_redundant_commits)
+               return 2;
+       else
+               return 0;
 }
 
 static struct {
@@ -1551,7 +1580,7 @@ static const char *command_to_string(const enum todo_command command)
 
 static char command_to_char(const enum todo_command command)
 {
-       if (command < TODO_COMMENT && todo_command_info[command].c)
+       if (command < TODO_COMMENT)
                return todo_command_info[command].c;
        return comment_line_char;
 }
@@ -1730,7 +1759,7 @@ static int do_pick_commit(struct repository *r,
        char *author = NULL;
        struct commit_message msg = { NULL, NULL, NULL, NULL };
        struct strbuf msgbuf = STRBUF_INIT;
-       int res, unborn = 0, reword = 0, allow;
+       int res, unborn = 0, reword = 0, allow, drop_commit;
 
        if (opts->no_commit) {
                /*
@@ -1916,7 +1945,9 @@ static int do_pick_commit(struct repository *r,
         * However, if the merge did not even start, then we don't want to
         * write it at all.
         */
-       if (command == TODO_PICK && !opts->no_commit && (res == 0 || res == 1) &&
+       if ((command == TODO_PICK || command == TODO_REWORD ||
+            command == TODO_EDIT) && !opts->no_commit &&
+           (res == 0 || res == 1) &&
            update_ref(NULL, "CHERRY_PICK_HEAD", &commit->object.oid, NULL,
                       REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
                res = -1;
@@ -1935,15 +1966,25 @@ static int do_pick_commit(struct repository *r,
                goto leave;
        }
 
+       drop_commit = 0;
        allow = allow_empty(r, opts, commit);
        if (allow < 0) {
                res = allow;
                goto leave;
-       } else if (allow)
+       } else if (allow == 1) {
                flags |= ALLOW_EMPTY;
-       if (!opts->no_commit) {
+       } else if (allow == 2) {
+               drop_commit = 1;
+               unlink(git_path_cherry_pick_head(r));
+               unlink(git_path_merge_msg(r));
+               fprintf(stderr,
+                       _("dropping %s %s -- patch contents already upstream\n"),
+                       oid_to_hex(&commit->object.oid), msg.subject);
+       } /* else allow == 0 and there's nothing special to do */
+       if (!opts->no_commit && !drop_commit) {
                if (author || command == TODO_REVERT || (flags & AMEND_MSG))
-                       res = do_commit(r, msg_file, author, opts, flags);
+                       res = do_commit(r, msg_file, author, opts, flags,
+                                       commit? &commit->object.oid : NULL);
                else
                        res = error(_("unable to parse commit author"));
                *check_todo = !!(flags & EDIT_MSG);
@@ -2496,6 +2537,12 @@ static int read_populate_opts(struct replay_opts *opts)
                if (file_exists(rebase_path_reschedule_failed_exec()))
                        opts->reschedule_failed_exec = 1;
 
+               if (file_exists(rebase_path_drop_redundant_commits()))
+                       opts->drop_redundant_commits = 1;
+
+               if (file_exists(rebase_path_keep_redundant_commits()))
+                       opts->keep_redundant_commits = 1;
+
                read_strategy_opts(opts, &buf);
                strbuf_release(&buf);
 
@@ -2547,8 +2594,6 @@ static void write_strategy_opts(struct replay_opts *opts)
 int write_basic_state(struct replay_opts *opts, const char *head_name,
                      struct commit *onto, const char *orig_head)
 {
-       const char *quiet = getenv("GIT_QUIET");
-
        if (head_name)
                write_file(rebase_path_head_name(), "%s\n", head_name);
        if (onto)
@@ -2557,8 +2602,8 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,
        if (orig_head)
                write_file(rebase_path_orig_head(), "%s\n", orig_head);
 
-       if (quiet)
-               write_file(rebase_path_quiet(), "%s\n", quiet);
+       if (opts->quiet)
+               write_file(rebase_path_quiet(), "%s", "");
        if (opts->verbose)
                write_file(rebase_path_verbose(), "%s", "");
        if (opts->strategy)
@@ -2575,6 +2620,10 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,
                write_file(rebase_path_gpg_sign_opt(), "-S%s\n", opts->gpg_sign);
        if (opts->signoff)
                write_file(rebase_path_signoff(), "--signoff\n");
+       if (opts->drop_redundant_commits)
+               write_file(rebase_path_drop_redundant_commits(), "%s", "");
+       if (opts->keep_redundant_commits)
+               write_file(rebase_path_keep_redundant_commits(), "%s", "");
        if (opts->reschedule_failed_exec)
                write_file(rebase_path_reschedule_failed_exec(), "%s", "");
 
@@ -2970,9 +3019,7 @@ static int make_patch(struct repository *r,
        p = short_commit_name(commit);
        if (write_message(p, strlen(p), rebase_path_stopped_sha(), 1) < 0)
                return -1;
-       if (update_ref("rebase", "REBASE_HEAD", &commit->object.oid,
-                      NULL, REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
-               res |= error(_("could not update %s"), "REBASE_HEAD");
+       res |= write_rebase_head(&commit->object.oid);
 
        strbuf_addf(&buf, "%s/patch", get_dir(opts));
        memset(&log_tree_opt, 0, sizeof(log_tree_opt));
@@ -3083,7 +3130,7 @@ static int do_exec(struct repository *r, const char *command_line)
        const char *child_argv[] = { NULL, NULL };
        int dirty, status;
 
-       fprintf(stderr, "Executing: %s\n", command_line);
+       fprintf(stderr, _("Executing: %s\n"), command_line);
        child_argv[0] = command_line;
        argv_array_pushf(&child_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
        argv_array_pushf(&child_env, "GIT_WORK_TREE=%s",
@@ -3174,7 +3221,7 @@ static int do_label(struct repository *r, const char *name, int len)
                return error(_("illegal label name: '%.*s'"), len, name);
 
        strbuf_addf(&ref_name, "refs/rewritten/%.*s", len, name);
-       strbuf_addf(&msg, "rebase -i (label) '%.*s'", len, name);
+       strbuf_addf(&msg, "rebase (label) '%.*s'", len, name);
 
        transaction = ref_store_transaction_begin(refs, &err);
        if (!transaction) {
@@ -3260,6 +3307,7 @@ static int do_reset(struct repository *r,
        unpack_tree_opts.fn = oneway_merge;
        unpack_tree_opts.merge = 1;
        unpack_tree_opts.update = 1;
+       init_checkout_metadata(&unpack_tree_opts.meta, name, &oid, NULL);
 
        if (repo_read_index_unmerged(r)) {
                rollback_lock_file(&lock);
@@ -3678,10 +3726,11 @@ static const char *reflog_message(struct replay_opts *opts,
 {
        va_list ap;
        static struct strbuf buf = STRBUF_INIT;
+       char *reflog_action = getenv(GIT_REFLOG_ACTION);
 
        va_start(ap, fmt);
        strbuf_reset(&buf);
-       strbuf_addstr(&buf, action_name(opts));
+       strbuf_addstr(&buf, reflog_action ? reflog_action : action_name(opts));
        if (sub_action)
                strbuf_addf(&buf, " (%s)", sub_action);
        if (fmt) {
@@ -3716,20 +3765,6 @@ static int run_git_checkout(struct repository *r, struct replay_opts *opts,
        return ret;
 }
 
-int prepare_branch_to_be_rebased(struct repository *r, struct replay_opts *opts,
-                                const char *commit)
-{
-       const char *action;
-
-       if (commit && *commit) {
-               action = reflog_message(opts, "start", "checkout %s", commit);
-               if (run_git_checkout(r, opts, commit, action))
-                       return error(_("could not checkout %s"), commit);
-       }
-
-       return 0;
-}
-
 static int checkout_onto(struct repository *r, struct replay_opts *opts,
                         const char *onto_name, const struct object_id *onto,
                         const char *orig_head)
@@ -3783,8 +3818,11 @@ static int pick_commits(struct repository *r,
                        struct replay_opts *opts)
 {
        int res = 0, reschedule = 0;
+       char *prev_reflog_action;
 
+       /* Note that 0 for 3rd parameter of setenv means set only if not set */
        setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
+       prev_reflog_action = xstrdup(getenv(GIT_REFLOG_ACTION));
        if (opts->allow_ff)
                assert(!(opts->signoff || opts->no_commit ||
                                opts->record_origin || opts->edit));
@@ -3809,7 +3847,7 @@ static int pick_commits(struct repository *r,
                                        fclose(f);
                                }
                                if (!opts->quiet)
-                                       fprintf(stderr, "Rebasing (%d/%d)%s",
+                                       fprintf(stderr, _("Rebasing (%d/%d)%s"),
                                                todo_list->done_nr,
                                                todo_list->total_nr,
                                                opts->verbose ? "\n" : "\r");
@@ -3829,12 +3867,14 @@ static int pick_commits(struct repository *r,
                }
                if (item->command <= TODO_SQUASH) {
                        if (is_rebase_i(opts))
-                               setenv("GIT_REFLOG_ACTION", reflog_message(opts,
+                               setenv(GIT_REFLOG_ACTION, reflog_message(opts,
                                        command_to_string(item->command), NULL),
                                        1);
                        res = do_pick_commit(r, item->command, item->commit,
                                             opts, is_final_fixup(todo_list),
                                             &check_todo);
+                       if (is_rebase_i(opts))
+                               setenv(GIT_REFLOG_ACTION, prev_reflog_action, 1);
                        if (is_rebase_i(opts) && res < 0) {
                                /* Reschedule */
                                advise(_(rescheduled_advice),
@@ -4061,7 +4101,7 @@ cleanup_head_ref:
                        if (!opts->verbose)
                                term_clear_line();
                        fprintf(stderr,
-                               "Successfully rebased and updated %s.\n",
+                               _("Successfully rebased and updated %s.\n"),
                                head_ref.buf);
                }
 
@@ -4239,6 +4279,14 @@ int sequencer_continue(struct repository *r, struct replay_opts *opts)
        if (is_rebase_i(opts)) {
                if ((res = read_populate_todo(r, &todo_list, opts)))
                        goto release_todo_list;
+
+               if (file_exists(rebase_path_dropped())) {
+                       if ((res = todo_list_check_against_backup(r, &todo_list)))
+                               goto release_todo_list;
+
+                       unlink(rebase_path_dropped());
+               }
+
                if (commit_staged_changes(r, opts, &todo_list)) {
                        res = -1;
                        goto release_todo_list;
@@ -4622,6 +4670,8 @@ static int make_script_with_merges(struct pretty_print_context *pp,
                is_empty = is_original_commit_empty(commit);
                if (!is_empty && (commit->object.flags & PATCHSAME))
                        continue;
+               if (is_empty && !keep_empty)
+                       continue;
 
                strbuf_reset(&oneline);
                pretty_print_commit(pp, commit, &oneline);
@@ -4630,11 +4680,12 @@ static int make_script_with_merges(struct pretty_print_context *pp,
                if (!to_merge) {
                        /* non-merge commit: easy case */
                        strbuf_reset(&buf);
-                       if (!keep_empty && is_empty)
-                               strbuf_addf(&buf, "%c ", comment_line_char);
                        strbuf_addf(&buf, "%s %s %s", cmd_pick,
                                    oid_to_hex(&commit->object.oid),
                                    oneline.buf);
+                       if (is_empty)
+                               strbuf_addf(&buf, " %c empty",
+                                           comment_line_char);
 
                        FLEX_ALLOC_STR(entry, string, buf.buf);
                        oidcpy(&entry->entry.oid, &commit->object.oid);
@@ -4801,12 +4852,13 @@ int sequencer_make_script(struct repository *r, struct strbuf *out, int argc,
        int keep_empty = flags & TODO_LIST_KEEP_EMPTY;
        const char *insn = flags & TODO_LIST_ABBREVIATE_CMDS ? "p" : "pick";
        int rebase_merges = flags & TODO_LIST_REBASE_MERGES;
+       int reapply_cherry_picks = flags & TODO_LIST_REAPPLY_CHERRY_PICKS;
 
        repo_init_revisions(r, &revs, NULL);
        revs.verbose_header = 1;
        if (!rebase_merges)
                revs.max_parents = 1;
-       revs.cherry_mark = 1;
+       revs.cherry_mark = !reapply_cherry_picks;
        revs.limited = 1;
        revs.reverse = 1;
        revs.right_only = 1;
@@ -4834,15 +4886,17 @@ int sequencer_make_script(struct repository *r, struct strbuf *out, int argc,
                return make_script_with_merges(&pp, &revs, out, flags);
 
        while ((commit = get_revision(&revs))) {
-               int is_empty  = is_original_commit_empty(commit);
+               int is_empty = is_original_commit_empty(commit);
 
                if (!is_empty && (commit->object.flags & PATCHSAME))
                        continue;
-               if (!keep_empty && is_empty)
-                       strbuf_addf(out, "%c ", comment_line_char);
+               if (is_empty && !keep_empty)
+                       continue;
                strbuf_addf(out, "%s %s ", insn,
                            oid_to_hex(&commit->object.oid));
                pretty_print_commit(&pp, commit, out);
+               if (is_empty)
+                       strbuf_addf(out, " %c empty", comment_line_char);
                strbuf_addch(out, '\n');
        }
        return 0;
@@ -4929,6 +4983,8 @@ static void todo_list_to_strbuf(struct repository *r, struct todo_list *todo_lis
                max = num;
 
        for (item = todo_list->items, i = 0; i < max; i++, item++) {
+               char cmd;
+
                /* if the item is not a command write it and continue */
                if (item->command >= TODO_COMMENT) {
                        strbuf_addf(buf, "%.*s\n", item->arg_len,
@@ -4937,8 +4993,9 @@ static void todo_list_to_strbuf(struct repository *r, struct todo_list *todo_lis
                }
 
                /* add command to the buffer */
-               if (flags & TODO_LIST_ABBREVIATE_CMDS)
-                       strbuf_addch(buf, command_to_char(item->command));
+               cmd = command_to_char(item->command);
+               if ((flags & TODO_LIST_ABBREVIATE_CMDS) && cmd)
+                       strbuf_addch(buf, cmd);
                else
                        strbuf_addstr(buf, command_to_string(item->command));
 
@@ -4976,7 +5033,7 @@ int todo_list_write_to_file(struct repository *r, struct todo_list *todo_list,
 
        todo_list_to_strbuf(r, todo_list, &buf, num, flags);
        if (flags & TODO_LIST_APPEND_TODO_HELP)
-               append_todo_help(flags & TODO_LIST_KEEP_EMPTY, count_commands(todo_list),
+               append_todo_help(count_commands(todo_list),
                                 shortrevisions, shortonto, &buf);
 
        res = write_message(buf.buf, buf.len, file, 0);
@@ -4985,41 +5042,6 @@ int todo_list_write_to_file(struct repository *r, struct todo_list *todo_list,
        return res;
 }
 
-static const char edit_todo_list_advice[] =
-N_("You can fix this with 'git rebase --edit-todo' "
-"and then run 'git rebase --continue'.\n"
-"Or you can abort the rebase with 'git rebase"
-" --abort'.\n");
-
-int check_todo_list_from_file(struct repository *r)
-{
-       struct todo_list old_todo = TODO_LIST_INIT, new_todo = TODO_LIST_INIT;
-       int res = 0;
-
-       if (strbuf_read_file_or_whine(&new_todo.buf, rebase_path_todo()) < 0) {
-               res = -1;
-               goto out;
-       }
-
-       if (strbuf_read_file_or_whine(&old_todo.buf, rebase_path_todo_backup()) < 0) {
-               res = -1;
-               goto out;
-       }
-
-       res = todo_list_parse_insn_buffer(r, old_todo.buf.buf, &old_todo);
-       if (!res)
-               res = todo_list_parse_insn_buffer(r, new_todo.buf.buf, &new_todo);
-       if (!res)
-               res = todo_list_check(&old_todo, &new_todo);
-       if (res)
-               fprintf(stderr, _(edit_todo_list_advice));
-out:
-       todo_list_release(&old_todo);
-       todo_list_release(&new_todo);
-
-       return res;
-}
-
 /* skip picking commits whose parents are unchanged */
 static int skip_unnecessary_picks(struct repository *r,
                                  struct todo_list *todo_list,
@@ -5117,11 +5139,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla
                todo_list_release(&new_todo);
 
                return error(_("nothing to do"));
-       }
-
-       if (todo_list_parse_insn_buffer(r, new_todo.buf.buf, &new_todo) ||
-           todo_list_check(todo_list, &new_todo)) {
-               fprintf(stderr, _(edit_todo_list_advice));
+       } else if (res == -4) {
                checkout_onto(r, opts, onto_name, &onto->object.oid, orig_head);
                todo_list_release(&new_todo);
 
@@ -5336,3 +5354,24 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)
 
        return 0;
 }
+
+int sequencer_determine_whence(struct repository *r, enum commit_whence *whence)
+{
+       if (file_exists(git_path_cherry_pick_head(r))) {
+               struct object_id cherry_pick_head, rebase_head;
+
+               if (file_exists(git_path_seq_dir()))
+                       *whence = FROM_CHERRY_PICK_MULTI;
+               if (file_exists(rebase_path()) &&
+                   !get_oid("REBASE_HEAD", &rebase_head) &&
+                   !get_oid("CHERRY_PICK_HEAD", &cherry_pick_head) &&
+                   oideq(&rebase_head, &cherry_pick_head))
+                       *whence = FROM_REBASE_PICK;
+               else
+                       *whence = FROM_CHERRY_PICK_SINGLE;
+
+               return 1;
+       }
+
+       return 0;
+}