bool io_read_buf(struct io *io, char buf[], size_t bufsize) { struct buffer result = {0}; if (io_get(io, &result, '\n', TRUE)) { result.data = chomp_string(result.data); string_ncopy_do(buf, bufsize, result.data, strlen(result.data)); } return io_done(io) && result.data; }
void string_copy_rev(char *dst, const char *src) { size_t srclen; if (!*src) return; for (srclen = 0; srclen < SIZEOF_REV; srclen++) if (!src[srclen] || isspace(src[srclen])) break; string_ncopy_do(dst, SIZEOF_REV, src, srclen); }
static enum status_code parse_string(char *opt, const char *arg, size_t optsize) { int arglen = strlen(arg); switch (arg[0]) { case '\"': case '\'': if (arglen == 1 || arg[arglen - 1] != arg[0]) return ERROR_UNMATCHED_QUOTATION; arg += 1; arglen -= 2; default: string_ncopy_do(opt, optsize, arg, arglen); return SUCCESS; } }
bool parse_blame_info(struct blame_commit *commit, char author[SIZEOF_STR], char *line) { if (match_blame_header("author ", &line)) { string_ncopy_do(author, SIZEOF_STR, line, strlen(line)); } else if (match_blame_header("author-mail ", &line)) { char *end = strchr(line, '>'); if (end) *end = 0; if (*line == '<') line++; commit->author = get_author(author, line); author[0] = 0; } else if (match_blame_header("author-time ", &line)) { parse_timesec(&commit->time, line); } else if (match_blame_header("author-tz ", &line)) { parse_timezone(&commit->time, line); } else if (match_blame_header("summary ", &line)) { string_ncopy(commit->title, line, strlen(line)); } else if (match_blame_header("previous ", &line)) { if (strlen(line) <= SIZEOF_REV) return FALSE; string_copy_rev(commit->parent_id, line); line += SIZEOF_REV; commit->parent_filename = get_path(line); if (!commit->parent_filename) return TRUE; } else if (match_blame_header("filename ", &line)) { commit->filename = get_path(line); return TRUE; } return FALSE; }
static enum status_code add_to_refs(const char *id, size_t idlen, char *name, size_t namelen, struct ref_opt *opt) { struct ref *ref = NULL; enum reference_type type = REFERENCE_BRANCH; void **ref_slot = NULL; if (!prefixcmp(name, "refs/tags/")) { type = REFERENCE_TAG; if (!suffixcmp(name, namelen, "^{}")) { namelen -= 3; name[namelen] = 0; } else { type = REFERENCE_LOCAL_TAG; } namelen -= STRING_SIZE("refs/tags/"); name += STRING_SIZE("refs/tags/"); } else if (!prefixcmp(name, "refs/remotes/")) { type = REFERENCE_REMOTE; namelen -= STRING_SIZE("refs/remotes/"); name += STRING_SIZE("refs/remotes/"); if (!strcmp(opt->remote, name)) type = REFERENCE_TRACKED_REMOTE; } else if (!prefixcmp(name, "refs/replace/")) { type = REFERENCE_REPLACE; id = name + strlen("refs/replace/"); idlen = namelen - strlen("refs/replace/"); name = "replaced"; namelen = strlen(name); } else if (!prefixcmp(name, "refs/heads/")) { namelen -= STRING_SIZE("refs/heads/"); name += STRING_SIZE("refs/heads/"); if (strlen(opt->head) == namelen && !strncmp(opt->head, name, namelen)) type = REFERENCE_HEAD; } else if (!strcmp(name, "HEAD")) { /* Handle the case of HEAD not being a symbolic ref, * i.e. during a rebase. */ if (*opt->head) return SUCCESS; type = REFERENCE_HEAD; } /* If we are reloading or it's an annotated tag, replace the * previous SHA1 with the resolved commit id; relies on the fact * git-ls-remote lists the commit id of an annotated tag right * before the commit id it points to. */ if (type == REFERENCE_REPLACE) { ref = string_map_remove(&refs_by_id, id); } else { ref_slot = string_map_put_to(&refs_by_name, name); if (!ref_slot) return ERROR_OUT_OF_MEMORY; ref = *ref_slot; } if (!ref) { ref = calloc(1, sizeof(*ref) + namelen); if (!ref) return ERROR_OUT_OF_MEMORY; strncpy(ref->name, name, namelen); if (ref_slot) *ref_slot = ref; } if (strncmp(ref->id, id, idlen) || ref->type != type) { opt->changed |= WATCH_REFS; if (*ref->id) remove_ref_from_id_map(ref); } ref->valid = true; ref->type = type; string_ncopy_do(ref->id, SIZEOF_REV, id, idlen); if (type == REFERENCE_HEAD) { if (!refs_head || (refs_head != ref && memcmp(refs_head, ref, sizeof(*ref)))) opt->changed |= WATCH_HEAD; refs_head = ref; } if (type == REFERENCE_TAG) refs_tags++; return add_ref_to_id_map(ref); }
static int add_to_refs(const char *id, size_t idlen, char *name, size_t namelen, struct ref_opt *opt) { struct ref *ref = NULL; enum reference_type type = REFERENCE_BRANCH; int pos; if (!prefixcmp(name, "refs/tags/")) { type = REFERENCE_TAG; if (!suffixcmp(name, namelen, "^{}")) { namelen -= 3; name[namelen] = 0; } else { type = REFERENCE_LOCAL_TAG; } namelen -= STRING_SIZE("refs/tags/"); name += STRING_SIZE("refs/tags/"); } else if (!prefixcmp(name, "refs/remotes/")) { type = REFERENCE_REMOTE; namelen -= STRING_SIZE("refs/remotes/"); name += STRING_SIZE("refs/remotes/"); if (!strcmp(opt->remote, name)) type = REFERENCE_TRACKED_REMOTE; } else if (!prefixcmp(name, "refs/replace/")) { type = REFERENCE_REPLACE; id = name + strlen("refs/replace/"); idlen = namelen - strlen("refs/replace/"); name = "replaced"; namelen = strlen(name); } else if (!prefixcmp(name, "refs/heads/")) { namelen -= STRING_SIZE("refs/heads/"); name += STRING_SIZE("refs/heads/"); if (strlen(opt->head) == namelen && !strncmp(opt->head, name, namelen)) type = REFERENCE_HEAD; } else if (!strcmp(name, "HEAD")) { /* Handle the case of HEAD not being a symbolic ref, * i.e. during a rebase. */ if (*opt->head) return OK; type = REFERENCE_HEAD; } /* If we are reloading or it's an annotated tag, replace the * previous SHA1 with the resolved commit id; relies on the fact * git-ls-remote lists the commit id of an annotated tag right * before the commit id it points to. */ for (pos = 0; pos < refs_size; pos++) { int cmp = type == REFERENCE_REPLACE ? strcmp(id, refs[pos]->id) : strcmp(name, refs[pos]->name); if (!cmp) { ref = refs[pos]; break; } } if (!ref) { if (!realloc_refs(&refs, refs_size, 1)) return ERR; ref = calloc(1, sizeof(*ref) + namelen); if (!ref) return ERR; refs[refs_size++] = ref; strncpy(ref->name, name, namelen); } if (strncmp(ref->id, id, idlen)) opt->changed |= WATCH_REFS; ref->valid = TRUE; ref->type = type; string_ncopy_do(ref->id, SIZEOF_REV, id, idlen); if (type == REFERENCE_HEAD) { if (!refs_head || (refs_head != ref && memcmp(refs_head, ref, sizeof(*ref)))) opt->changed |= WATCH_HEAD; refs_head = ref; } return OK; }
static char * prompt_input(const char *prompt, struct input *input) { enum input_status status = INPUT_OK; unsigned char chars_length[SIZEOF_STR]; struct key key; size_t promptlen = strlen(prompt); int pos = 0, chars = 0; input->buf[pos] = 0; while (status == INPUT_OK || status == INPUT_SKIP) { update_status("%s%.*s", prompt, pos, input->buf); if (get_input(pos + promptlen, &key, FALSE) == OK) { int len = strlen(key.data.bytes); if (pos + len >= sizeof(input->buf)) { report("Input string too long"); return NULL; } string_ncopy_do(input->buf + pos, sizeof(input->buf) - pos, key.data.bytes, len); pos += len; chars_length[chars++] = len; status = input->handler(input, &key); if (status != INPUT_OK) { pos -= len; chars--; } else { int changed_pos = strlen(input->buf); if (changed_pos != pos) { pos = changed_pos; chars_length[chars - 1] = changed_pos - (pos - len); } } } else { status = input->handler(input, &key); if (status == INPUT_DELETE) { int len = chars_length[--chars]; pos -= len; status = INPUT_OK; } else { int changed_pos = strlen(input->buf); if (changed_pos != pos) { pos = changed_pos; chars_length[chars++] = changed_pos - pos; } } } input->buf[pos] = 0; } report_clear(); if (status == INPUT_CANCEL) return NULL; input->buf[pos++] = 0; return input->buf; }
static int add_to_refs(const char *id, size_t idlen, char *name, size_t namelen, struct ref_opt *opt) { struct ref *ref = NULL; bool tag = FALSE; bool ltag = FALSE; bool remote = FALSE; bool replace = FALSE; bool tracked = FALSE; bool head = FALSE; int pos; if (!prefixcmp(name, "refs/tags/")) { if (!suffixcmp(name, namelen, "^{}")) { namelen -= 3; name[namelen] = 0; } else { ltag = TRUE; } tag = TRUE; namelen -= STRING_SIZE("refs/tags/"); name += STRING_SIZE("refs/tags/"); } else if (!prefixcmp(name, "refs/remotes/")) { remote = TRUE; namelen -= STRING_SIZE("refs/remotes/"); name += STRING_SIZE("refs/remotes/"); tracked = !strcmp(opt->remote, name); } else if (!prefixcmp(name, "refs/replace/")) { replace = TRUE; id = name + strlen("refs/replace/"); idlen = namelen - strlen("refs/replace/"); name = "replaced"; namelen = strlen(name); } else if (!prefixcmp(name, "refs/heads/")) { namelen -= STRING_SIZE("refs/heads/"); name += STRING_SIZE("refs/heads/"); head = strlen(opt->head) == namelen && !strncmp(opt->head, name, namelen); } else if (!strcmp(name, "HEAD")) { /* Handle the case of HEAD not being a symbolic ref, * i.e. during a rebase. */ if (*opt->head) return OK; head = TRUE; } /* If we are reloading or it's an annotated tag, replace the * previous SHA1 with the resolved commit id; relies on the fact * git-ls-remote lists the commit id of an annotated tag right * before the commit id it points to. */ for (pos = 0; pos < refs_size; pos++) { int cmp = replace ? strcmp(id, refs[pos]->id) : strcmp(name, refs[pos]->name); if (!cmp) { ref = refs[pos]; break; } } if (!ref) { if (!realloc_refs(&refs, refs_size, 1)) return ERR; ref = calloc(1, sizeof(*ref) + namelen); if (!ref) return ERR; refs[refs_size++] = ref; strncpy(ref->name, name, namelen); } ref->valid = TRUE; ref->head = head; ref->tag = tag; ref->ltag = ltag; ref->remote = remote; ref->replace = replace; ref->tracked = tracked; string_ncopy_do(ref->id, SIZEOF_REV, id, idlen); if (head) refs_head = ref; return OK; }
static char * prompt_input(const char *prompt, input_handler handler, void *data) { enum input_status status = INPUT_OK; static char buf[SIZEOF_STR]; unsigned char chars_length[SIZEOF_STR]; struct key_input input; size_t promptlen = strlen(prompt); int pos = 0, chars = 0; buf[pos] = 0; while (status == INPUT_OK || status == INPUT_SKIP) { update_status("%s%.*s", prompt, pos, buf); switch (get_input(pos + promptlen, &input, FALSE)) { case KEY_RETURN: case KEY_ENTER: case '\n': status = pos ? INPUT_STOP : INPUT_CANCEL; break; case KEY_BACKSPACE: if (pos > 0) { int len = chars_length[--chars]; pos -= len; buf[pos] = 0; } else { status = INPUT_CANCEL; } break; case KEY_ESC: status = INPUT_CANCEL; break; default: if (pos >= sizeof(buf)) { report("Input string too long"); return NULL; } status = handler(data, buf, &input); if (status == INPUT_OK) { int len = strlen(input.data.bytes); string_ncopy_do(buf + pos, sizeof(buf) - pos, input.data.bytes, len); pos += len; chars_length[chars++] = len; } } } report_clear(); if (status == INPUT_CANCEL) return NULL; buf[pos++] = 0; return buf; }