diff options
Diffstat (limited to 'builtin')
-rw-r--r-- | builtin/checkout.c | 3 | ||||
-rw-r--r-- | builtin/fmt-merge-msg.c | 159 | ||||
-rw-r--r-- | builtin/grep.c | 15 | ||||
-rw-r--r-- | builtin/log.c | 39 | ||||
-rw-r--r-- | builtin/ls-files.c | 7 | ||||
-rw-r--r-- | builtin/ls-tree.c | 6 | ||||
-rw-r--r-- | builtin/merge-file.c | 6 | ||||
-rw-r--r-- | builtin/rev-list.c | 7 | ||||
-rw-r--r-- | builtin/revert.c | 103 |
9 files changed, 169 insertions, 176 deletions
diff --git a/builtin/checkout.c b/builtin/checkout.c index acefaaf41a..88b1f43e05 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -149,7 +149,7 @@ static int checkout_merged(int pos, struct checkout *state) read_mmblob(&ours, active_cache[pos+1]->sha1); read_mmblob(&theirs, active_cache[pos+2]->sha1); - status = ll_merge(&result_buf, path, &ancestor, + status = ll_merge(&result_buf, path, &ancestor, "base", &ours, "ours", &theirs, "theirs", 0); free(ancestor.ptr); free(ours.ptr); @@ -439,6 +439,7 @@ static int merge_working_tree(struct checkout_opts *opts, ret = reset_tree(new->commit->tree, opts, 1); if (ret) return ret; + o.ancestor = old->name; o.branch1 = new->name; o.branch2 = "local"; merge_trees(&o, new->commit->tree, work, diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index 9d524000b5..379a03131f 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -4,6 +4,7 @@ #include "diff.h" #include "revision.h" #include "tag.h" +#include "string-list.h" static const char * const fmt_merge_msg_usage[] = { "git fmt-merge-msg [--log|--no-log] [--file <file>]", @@ -24,58 +25,21 @@ static int fmt_merge_msg_config(const char *key, const char *value, void *cb) return 0; } -struct list { - char **list; - void **payload; - unsigned nr, alloc; +struct src_data { + struct string_list branch, tag, r_branch, generic; + int head_status; }; -static void append_to_list(struct list *list, char *value, void *payload) -{ - if (list->nr == list->alloc) { - list->alloc += 32; - list->list = xrealloc(list->list, sizeof(char *) * list->alloc); - list->payload = xrealloc(list->payload, - sizeof(char *) * list->alloc); - } - list->payload[list->nr] = payload; - list->list[list->nr++] = value; -} - -static int find_in_list(struct list *list, char *value) -{ - int i; - - for (i = 0; i < list->nr; i++) - if (!strcmp(list->list[i], value)) - return i; - - return -1; -} - -static void free_list(struct list *list) +void init_src_data(struct src_data *data) { - int i; - - if (list->alloc == 0) - return; - - for (i = 0; i < list->nr; i++) { - free(list->list[i]); - free(list->payload[i]); - } - free(list->list); - free(list->payload); - list->nr = list->alloc = 0; + data->branch.strdup_strings = 1; + data->tag.strdup_strings = 1; + data->r_branch.strdup_strings = 1; + data->generic.strdup_strings = 1; } -struct src_data { - struct list branch, tag, r_branch, generic; - int head_status; -}; - -static struct list srcs = { NULL, NULL, 0, 0}; -static struct list origins = { NULL, NULL, 0, 0}; +static struct string_list srcs = { NULL, 0, 0, 1 }; +static struct string_list origins = { NULL, 0, 0, 1 }; static int handle_line(char *line) { @@ -83,6 +47,7 @@ static int handle_line(char *line) unsigned char *sha1; char *src, *origin; struct src_data *src_data; + struct string_list_item *item; int pulling_head = 0; if (len < 43 || line[40] != '\t') @@ -115,64 +80,62 @@ static int handle_line(char *line) pulling_head = 1; } - i = find_in_list(&srcs, src); - if (i < 0) { - i = srcs.nr; - append_to_list(&srcs, xstrdup(src), - xcalloc(1, sizeof(struct src_data))); + item = unsorted_string_list_lookup(&srcs, src); + if (!item) { + item = string_list_append(src, &srcs); + item->util = xcalloc(1, sizeof(struct src_data)); + init_src_data(item->util); } - src_data = srcs.payload[i]; + src_data = item->util; if (pulling_head) { - origin = xstrdup(src); + origin = src; src_data->head_status |= 1; } else if (!prefixcmp(line, "branch ")) { - origin = xstrdup(line + 7); - append_to_list(&src_data->branch, origin, NULL); + origin = line + 7; + string_list_append(origin, &src_data->branch); src_data->head_status |= 2; } else if (!prefixcmp(line, "tag ")) { origin = line; - append_to_list(&src_data->tag, xstrdup(origin + 4), NULL); + string_list_append(origin + 4, &src_data->tag); src_data->head_status |= 2; } else if (!prefixcmp(line, "remote branch ")) { - origin = xstrdup(line + 14); - append_to_list(&src_data->r_branch, origin, NULL); + origin = line + 14; + string_list_append(origin, &src_data->r_branch); src_data->head_status |= 2; } else { - origin = xstrdup(src); - append_to_list(&src_data->generic, xstrdup(line), NULL); + origin = src; + string_list_append(line, &src_data->generic); src_data->head_status |= 2; } if (!strcmp(".", src) || !strcmp(src, origin)) { int len = strlen(origin); - if (origin[0] == '\'' && origin[len - 1] == '\'') { + if (origin[0] == '\'' && origin[len - 1] == '\'') origin = xmemdupz(origin + 1, len - 2); - } else { - origin = xstrdup(origin); - } } else { char *new_origin = xmalloc(strlen(origin) + strlen(src) + 5); sprintf(new_origin, "%s of %s", origin, src); origin = new_origin; } - append_to_list(&origins, origin, sha1); + string_list_append(origin, &origins)->util = sha1; return 0; } static void print_joined(const char *singular, const char *plural, - struct list *list, struct strbuf *out) + struct string_list *list, struct strbuf *out) { if (list->nr == 0) return; if (list->nr == 1) { - strbuf_addf(out, "%s%s", singular, list->list[0]); + strbuf_addf(out, "%s%s", singular, list->items[0].string); } else { int i; strbuf_addstr(out, plural); for (i = 0; i < list->nr - 1; i++) - strbuf_addf(out, "%s%s", i > 0 ? ", " : "", list->list[i]); - strbuf_addf(out, " and %s", list->list[list->nr - 1]); + strbuf_addf(out, "%s%s", i > 0 ? ", " : "", + list->items[i].string); + strbuf_addf(out, " and %s", list->items[list->nr - 1].string); } } @@ -183,8 +146,9 @@ static void shortlog(const char *name, unsigned char *sha1, int i, count = 0; struct commit *commit; struct object *branch; - struct list subjects = { NULL, NULL, 0, 0 }; + struct string_list subjects = { NULL, 0, 0, 1 }; int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED; + struct strbuf sb = STRBUF_INIT; branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40); if (!branch || branch->type != OBJ_COMMIT) @@ -198,7 +162,7 @@ static void shortlog(const char *name, unsigned char *sha1, if (prepare_revision_walk(rev)) die("revision walk setup failed"); while ((commit = get_revision(rev)) != NULL) { - char *oneline, *bol, *eol; + struct pretty_print_context ctx = {0}; /* ignore merges */ if (commit->parents && commit->parents->next) @@ -208,30 +172,14 @@ static void shortlog(const char *name, unsigned char *sha1, if (subjects.nr > limit) continue; - bol = strstr(commit->buffer, "\n\n"); - if (bol) { - unsigned char c; - do { - c = *++bol; - } while (isspace(c)); - if (!c) - bol = NULL; - } - - if (!bol) { - append_to_list(&subjects, xstrdup(sha1_to_hex( - commit->object.sha1)), - NULL); - continue; - } + format_commit_message(commit, "%s", &sb, &ctx); + strbuf_ltrim(&sb); - eol = strchr(bol, '\n'); - if (eol) { - oneline = xmemdupz(bol, eol - bol); - } else { - oneline = xstrdup(bol); - } - append_to_list(&subjects, oneline, NULL); + if (!sb.len) + string_list_append(sha1_to_hex(commit->object.sha1), + &subjects); + else + string_list_append(strbuf_detach(&sb, NULL), &subjects); } if (count > limit) @@ -243,7 +191,7 @@ static void shortlog(const char *name, unsigned char *sha1, if (i >= limit) strbuf_addf(out, " ...\n"); else - strbuf_addf(out, " %s\n", subjects.list[i]); + strbuf_addf(out, " %s\n", subjects.items[i].string); clear_commit_marks((struct commit *)branch, flags); clear_commit_marks(head, flags); @@ -251,7 +199,7 @@ static void shortlog(const char *name, unsigned char *sha1, rev->commits = NULL; rev->pending.nr = 0; - free_list(&subjects); + string_list_clear(&subjects, 0); } int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) { @@ -281,16 +229,19 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) { die ("Error in line %d: %.*s", i, len, p); } + if (!srcs.nr) + return 0; + strbuf_addstr(out, "Merge "); for (i = 0; i < srcs.nr; i++) { - struct src_data *src_data = srcs.payload[i]; + struct src_data *src_data = srcs.items[i].util; const char *subsep = ""; strbuf_addstr(out, sep); sep = "; "; if (src_data->head_status == 1) { - strbuf_addstr(out, srcs.list[i]); + strbuf_addstr(out, srcs.items[i].string); continue; } if (src_data->head_status == 3) { @@ -319,8 +270,8 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) { print_joined("commit ", "commits ", &src_data->generic, out); } - if (strcmp(".", srcs.list[i])) - strbuf_addf(out, " of %s", srcs.list[i]); + if (strcmp(".", srcs.items[i].string)) + strbuf_addf(out, " of %s", srcs.items[i].string); } if (!strcmp("master", current_branch)) @@ -339,7 +290,7 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) { rev.limited = 1; for (i = 0; i < origins.nr; i++) - shortlog(origins.list[i], origins.payload[i], + shortlog(origins.items[i].string, origins.items[i].util, head, &rev, limit, out); } return 0; @@ -350,7 +301,9 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix) const char *inpath = NULL; struct option options[] = { OPT_BOOLEAN(0, "log", &merge_summary, "populate log with the shortlog"), - OPT_BOOLEAN(0, "summary", &merge_summary, "alias for --log"), + { OPTION_BOOLEAN, 0, "summary", &merge_summary, NULL, + "alias for --log (deprecated)", + PARSE_OPT_NOARG | PARSE_OPT_HIDDEN }, OPT_FILENAME('F', "file", &inpath, "file to read from"), OPT_END() }; diff --git a/builtin/grep.c b/builtin/grep.c index 9d30ddb28d..8e928e2170 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -96,6 +96,9 @@ static pthread_cond_t cond_write; /* Signalled when we are finished with everything. */ static pthread_cond_t cond_result; +static int print_hunk_marks_between_files; +static int printed_something; + static void add_work(enum work_type type, char *name, void *id) { grep_lock(); @@ -159,7 +162,12 @@ static void work_done(struct work_item *w) for(; todo[todo_done].done && todo_done != todo_start; todo_done = (todo_done+1) % ARRAY_SIZE(todo)) { w = &todo[todo_done]; - write_or_die(1, w->out.buf, w->out.len); + if (w->out.len) { + if (print_hunk_marks_between_files && printed_something) + write_or_die(1, "--\n", 3); + write_or_die(1, w->out.buf, w->out.len); + printed_something = 1; + } free(w->name); free(w->identifier); } @@ -946,8 +954,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (online_cpus() == 1 || !grep_threads_ok(&opt)) use_threads = 0; - if (use_threads) + if (use_threads) { + if (opt.pre_context || opt.post_context) + print_hunk_marks_between_files = 1; start_threads(&opt); + } #else use_threads = 0; #endif diff --git a/builtin/log.c b/builtin/log.c index 542ecc708b..b706a5ff88 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -1303,8 +1303,11 @@ static int add_pending_commit(const char *arg, struct rev_info *revs, int flags) return -1; } -static const char cherry_usage[] = -"git cherry [-v] [<upstream> [<head> [<limit>]]]"; +static const char * const cherry_usage[] = { + "git cherry [-v] [<upstream> [<head> [<limit>]]]", + NULL +}; + int cmd_cherry(int argc, const char **argv, const char *prefix) { struct rev_info revs; @@ -1315,26 +1318,25 @@ int cmd_cherry(int argc, const char **argv, const char *prefix) const char *upstream; const char *head = "HEAD"; const char *limit = NULL; - int verbose = 0; + int verbose = 0, abbrev = 0; - if (argc > 1 && !strcmp(argv[1], "-v")) { - verbose = 1; - argc--; - argv++; - } + struct option options[] = { + OPT__ABBREV(&abbrev), + OPT__VERBOSE(&verbose), + OPT_END() + }; - if (argc > 1 && !strcmp(argv[1], "-h")) - usage(cherry_usage); + argc = parse_options(argc, argv, prefix, options, cherry_usage, 0); switch (argc) { - case 4: - limit = argv[3]; - /* FALLTHROUGH */ case 3: - head = argv[2]; + limit = argv[2]; /* FALLTHROUGH */ case 2: - upstream = argv[1]; + head = argv[1]; + /* FALLTHROUGH */ + case 1: + upstream = argv[0]; break; default: current_branch = branch_get(NULL); @@ -1344,7 +1346,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix) fprintf(stderr, "Could not find a tracked" " remote branch, please" " specify <upstream> manually.\n"); - usage(cherry_usage); + usage_with_options(cherry_usage, options); } upstream = current_branch->merge[0]->dst; @@ -1397,12 +1399,13 @@ int cmd_cherry(int argc, const char **argv, const char *prefix) pretty_print_commit(CMIT_FMT_ONELINE, commit, &buf, &ctx); printf("%c %s %s\n", sign, - sha1_to_hex(commit->object.sha1), buf.buf); + find_unique_abbrev(commit->object.sha1, abbrev), + buf.buf); strbuf_release(&buf); } else { printf("%c %s\n", sign, - sha1_to_hex(commit->object.sha1)); + find_unique_abbrev(commit->object.sha1, abbrev)); } list = list->next; diff --git a/builtin/ls-files.c b/builtin/ls-files.c index b065061392..c0fbcdcf4f 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -153,8 +153,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce) printf("%s%06o %s %d\t", tag, ce->ce_mode, - abbrev ? find_unique_abbrev(ce->sha1,abbrev) - : sha1_to_hex(ce->sha1), + find_unique_abbrev(ce->sha1,abbrev), ce_stage(ce)); } write_name_quoted(ce->name + offset, stdout, line_terminator); @@ -176,9 +175,7 @@ static int show_one_ru(struct string_list_item *item, void *cbdata) if (!ui->mode[i]) continue; printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i], - abbrev - ? find_unique_abbrev(ui->sha1[i], abbrev) - : sha1_to_hex(ui->sha1[i]), + find_unique_abbrev(ui->sha1[i], abbrev), i + 1); write_name_quoted(path + offset, stdout, line_terminator); } diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c index 4484185afc..dc86b0d9a9 100644 --- a/builtin/ls-tree.c +++ b/builtin/ls-tree.c @@ -103,13 +103,11 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen, } else strcpy(size_text, "-"); printf("%06o %s %s %7s\t", mode, type, - abbrev ? find_unique_abbrev(sha1, abbrev) - : sha1_to_hex(sha1), + find_unique_abbrev(sha1, abbrev), size_text); } else printf("%06o %s %s\t", mode, type, - abbrev ? find_unique_abbrev(sha1, abbrev) - : sha1_to_hex(sha1)); + find_unique_abbrev(sha1, abbrev)); } write_name_quotedpfx(base + chomp_prefix, baselen - chomp_prefix, pathname, stdout, line_termination); diff --git a/builtin/merge-file.c b/builtin/merge-file.c index 69cc683332..610849a653 100644 --- a/builtin/merge-file.c +++ b/builtin/merge-file.c @@ -77,8 +77,10 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix) argv[i]); } - ret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2], - &xmp, &result); + xmp.ancestor = names[1]; + xmp.file1 = names[0]; + xmp.file2 = names[2]; + ret = xdl_merge(mmfs + 1, mmfs + 0, mmfs + 2, &xmp, &result); for (i = 0; i < 3; i++) free(mmfs[i].ptr); diff --git a/builtin/rev-list.c b/builtin/rev-list.c index 5679170e82..51ceb19d88 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -133,9 +133,12 @@ static void show_commit(struct commit *commit, void *data) */ if (graph_show_remainder(revs->graph)) putchar('\n'); + if (revs->commit_format == CMIT_FMT_ONELINE) + putchar('\n'); } } else { - if (buf.len) + if (revs->commit_format != CMIT_FMT_USERFORMAT || + buf.len) printf("%s%c", buf.buf, info->hdr_termination); } strbuf_release(&buf); @@ -313,7 +316,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) git_config(git_default_config, NULL); init_revisions(&revs, prefix); - revs.abbrev = 0; + revs.abbrev = DEFAULT_ABBREV; revs.commit_format = CMIT_FMT_UNSPECIFIED; argc = setup_revisions(argc, argv, &revs, NULL); diff --git a/builtin/revert.c b/builtin/revert.c index 9a3c14c329..778a56eb51 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -46,6 +46,8 @@ static const char *me; #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION" +static char *get_encoding(const char *message); + static void parse_args(int argc, const char **argv) { const char * const * usage_str = @@ -85,33 +87,64 @@ static void parse_args(int argc, const char **argv) exit(1); } -static char *get_oneline(const char *message) +struct commit_message { + char *parent_label; + const char *label; + const char *subject; + char *reencoded_message; + const char *message; +}; + +static int get_message(const char *raw_message, struct commit_message *out) { - char *result; - const char *p = message, *abbrev, *eol; + const char *encoding; + const char *p, *abbrev, *eol; + char *q; int abbrev_len, oneline_len; - if (!p) - die ("Could not read commit message of %s", - sha1_to_hex(commit->object.sha1)); + if (!raw_message) + return -1; + encoding = get_encoding(raw_message); + if (!encoding) + encoding = "UTF-8"; + if (!git_commit_encoding) + git_commit_encoding = "UTF-8"; + if ((out->reencoded_message = reencode_string(raw_message, + git_commit_encoding, encoding))) + out->message = out->reencoded_message; + + abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV); + abbrev_len = strlen(abbrev); + + /* Find beginning and end of commit subject. */ + p = out->message; while (*p && (*p != '\n' || p[1] != '\n')) p++; - if (*p) { p += 2; for (eol = p + 1; *eol && *eol != '\n'; eol++) ; /* do nothing */ } else eol = p; - abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV); - abbrev_len = strlen(abbrev); oneline_len = eol - p; - result = xmalloc(abbrev_len + 5 + oneline_len); - memcpy(result, abbrev, abbrev_len); - memcpy(result + abbrev_len, "... ", 4); - memcpy(result + abbrev_len + 4, p, oneline_len); - result[abbrev_len + 4 + oneline_len] = '\0'; - return result; + + out->parent_label = xmalloc(strlen("parent of ") + abbrev_len + + strlen("... ") + oneline_len + 1); + q = out->parent_label; + q = mempcpy(q, "parent of ", strlen("parent of ")); + out->label = q; + q = mempcpy(q, abbrev, abbrev_len); + q = mempcpy(q, "... ", strlen("... ")); + out->subject = q; + q = mempcpy(q, p, oneline_len); + *q = '\0'; + return 0; +} + +static void free_message(struct commit_message *msg) +{ + free(msg->parent_label); + free(msg->reencoded_message); } static char *get_encoding(const char *message) @@ -271,9 +304,9 @@ static int revert_or_cherry_pick(int argc, const char **argv) { unsigned char head[20]; struct commit *base, *next, *parent; + const char *base_label, *next_label; int i, index_fd, clean; - char *oneline, *reencoded_message = NULL; - const char *message, *encoding; + struct commit_message msg = { NULL, NULL, NULL, NULL, NULL }; char *defmsg = NULL; struct merge_options o; struct tree *result, *next_tree, *base_tree, *head_tree; @@ -349,14 +382,14 @@ static int revert_or_cherry_pick(int argc, const char **argv) if (allow_ff && !hashcmp(parent->object.sha1, head)) return fast_forward_to(commit->object.sha1, head); - if (!(message = commit->buffer)) - die ("Cannot get commit message for %s", - sha1_to_hex(commit->object.sha1)); - if (parent && parse_commit(parent) < 0) die("%s: cannot parse parent commit %s", me, sha1_to_hex(parent->object.sha1)); + if (get_message(commit->buffer, &msg) != 0) + die("Cannot get commit message for %s", + sha1_to_hex(commit->object.sha1)); + /* * "commit" is an existing commit. We would want to apply * the difference it introduces since its first parent "prev" @@ -368,26 +401,15 @@ static int revert_or_cherry_pick(int argc, const char **argv) msg_fd = hold_lock_file_for_update(&msg_file, defmsg, LOCK_DIE_ON_ERROR); - encoding = get_encoding(message); - if (!encoding) - encoding = "UTF-8"; - if (!git_commit_encoding) - git_commit_encoding = "UTF-8"; - if ((reencoded_message = reencode_string(message, - git_commit_encoding, encoding))) - message = reencoded_message; - - oneline = get_oneline(message); - index_fd = hold_locked_index(&index_lock, 1); if (action == REVERT) { - char *oneline_body = strchr(oneline, ' '); - base = commit; + base_label = msg.label; next = parent; + next_label = msg.parent_label; add_to_msg("Revert \""); - add_to_msg(oneline_body + 1); + add_to_msg(msg.subject); add_to_msg("\"\n\nThis reverts commit "); add_to_msg(sha1_to_hex(commit->object.sha1)); @@ -398,9 +420,11 @@ static int revert_or_cherry_pick(int argc, const char **argv) add_to_msg(".\n"); } else { base = parent; + base_label = msg.parent_label; next = commit; - set_author_ident_env(message); - add_message_to_msg(message); + next_label = msg.label; + set_author_ident_env(msg.message); + add_message_to_msg(msg.message); if (no_replay) { add_to_msg("(cherry picked from commit "); add_to_msg(sha1_to_hex(commit->object.sha1)); @@ -410,8 +434,9 @@ static int revert_or_cherry_pick(int argc, const char **argv) read_cache(); init_merge_options(&o); + o.ancestor = base ? base_label : "(empty tree)"; o.branch1 = "HEAD"; - o.branch2 = oneline; + o.branch2 = next ? next_label : "(empty tree)"; head_tree = parse_tree_indirect(head); next_tree = next ? next->tree : empty_tree(); @@ -475,7 +500,7 @@ static int revert_or_cherry_pick(int argc, const char **argv) args[i] = NULL; return execv_git_cmd(args); } - free(reencoded_message); + free_message(&msg); free(defmsg); return 0; |