+}
+
+
+/*
+ * Repository references
+ */
+
+static struct ref *refs;
+static size_t refs_size;
+
+static struct ref **
+get_refs(char *id)
+{
+ struct ref **id_refs = NULL;
+ size_t id_refs_size = 0;
+ size_t i;
+
+ for (i = 0; i < refs_size; i++) {
+ struct ref **tmp;
+
+ if (strcmp(id, refs[i].id))
+ continue;
+
+ tmp = realloc(id_refs, (id_refs_size + 1) * sizeof(*id_refs));
+ if (!tmp) {
+ if (id_refs)
+ free(id_refs);
+ return NULL;
+ }
+
+ id_refs = tmp;
+ if (id_refs_size > 0)
+ id_refs[id_refs_size - 1]->next = 1;
+ id_refs[id_refs_size] = &refs[i];
+
+ /* XXX: The properties of the commit chains ensures that we can
+ * safely modify the shared ref. The repo references will
+ * always be similar for the same id. */
+ id_refs[id_refs_size]->next = 0;
+ id_refs_size++;
+ }
+
+ return id_refs;
+}
+
+static int
+load_refs(void)
+{
+ const char *cmd_env = getenv("TIG_LS_REMOTE");
+ const char *cmd = cmd_env && *cmd_env ? cmd_env : TIG_LS_REMOTE;
+ FILE *pipe = popen(cmd, "r");
+ char buffer[BUFSIZ];
+ char *line;
+
+ if (!pipe)
+ return ERR;
+
+ while ((line = fgets(buffer, sizeof(buffer), pipe))) {
+ char *name = strchr(line, '\t');
+ struct ref *ref;
+ int namelen;
+ bool tag = FALSE;
+ bool tag_commit = FALSE;
+
+ if (!name)
+ continue;
+
+ *name++ = 0;
+ namelen = strlen(name) - 1;
+
+ /* Commits referenced by tags has "^{}" appended. */
+ if (name[namelen - 1] == '}') {
+ while (namelen > 0 && name[namelen] != '^')
+ namelen--;
+ if (namelen > 0)
+ tag_commit = TRUE;
+ }
+ name[namelen] = 0;
+
+ if (!strncmp(name, "refs/tags/", STRING_SIZE("refs/tags/"))) {
+ if (!tag_commit)
+ continue;
+ name += STRING_SIZE("refs/tags/");
+ tag = TRUE;
+
+ } else if (!strncmp(name, "refs/heads/", STRING_SIZE("refs/heads/"))) {
+ name += STRING_SIZE("refs/heads/");
+
+ } else if (!strcmp(name, "HEAD")) {
+ continue;
+ }
+
+ refs = realloc(refs, sizeof(*refs) * (refs_size + 1));
+ if (!refs)
+ return ERR;
+
+ ref = &refs[refs_size++];
+ ref->tag = tag;
+ ref->name = strdup(name);
+ if (!ref->name)
+ return ERR;
+
+ string_copy(ref->id, line);
+ }
+
+ if (ferror(pipe))
+ return ERR;
+
+ pclose(pipe);
+
+ if (refs_size == 0)
+ die("Not a git repository");
+
+ return OK;
+}
+
+/*
+ * Main
+ */
+
+#if __GNUC__ >= 3
+#define __NORETURN __attribute__((__noreturn__))
+#else
+#define __NORETURN
+#endif
+
+static void __NORETURN
+quit(int sig)
+{
+ /* XXX: Restore tty modes and let the OS cleanup the rest! */
+ if (cursed)
+ endwin();
+ exit(0);
+}
+
+static void __NORETURN
+die(const char *err, ...)
+{
+ va_list args;
+
+ endwin();
+
+ va_start(args, err);
+ fputs("tig: ", stderr);
+ vfprintf(stderr, err, args);
+ fputs("\n", stderr);
+ va_end(args);
+
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct view *view;
+ enum request request;
+ size_t i;
+
+ signal(SIGINT, quit);
+
+ if (!parse_options(argc, argv))
+ return 0;
+
+ if (load_refs() == ERR)
+ die("Failed to load refs.");
+
+ for (i = 0; i < ARRAY_SIZE(views) && (view = &views[i]); i++)
+ view->cmd_env = getenv(view->cmd_env);
+
+ request = opt_request;
+
+ init_display();