diff options
Diffstat (limited to 'git.c')
-rw-r--r-- | git.c | 244 |
1 files changed, 243 insertions, 1 deletions
@@ -72,8 +72,250 @@ void free_files(file **files) { free(files); } -pull_request *get_pull_request(int id, const char *root) { +static linked_list *parse_dsv_str(const char *str, const char *delm) { + linked_list *tail = NULL; + for (; *str != '\0'; str += strspn(str, delm)) { + /* Get the length of the token. */ + size_t tok_len = strcspn(str, delm); + /* Create the token. */ + char *tok = calloc(tok_len+1, sizeof(char)); + /* Get the token from the string. */ + memcpy(tok, tmp, tok_len); + /* Add the token to the list.. */ + tail = add_node(&tail, tok); + /* Move over the token. */ + str += tok_len; + } + return tail; +} + +static void parse_patch_list(void *ctx, void *ret, const keyword *key, keyword_val val) { + /* Do we actually have a "patches" keyword? */ + if (key->type == TYPE_STRING) { + const char *root = (const char *)ctx; + pull_request *pr = (pull_request *)ret; + /* Is the supplied string non-empty? */ + if (!is_empty(val.str)) { + /* Parse the patch list. */ + linked_list *patch_list = parse_dsv_str(val.str, " \t\v"); + /* Get the number of patch files in the list. */ + int num_patches = linked_list_size(patch_list); + + /* Create the patch list. */ + pr->patches = calloc(num_patches+1, sizeof(file *)); + /* Set the last entry to NULL, to denote the end of the list. */ + pr->patches[num_patches--] = NULL; + /* For each patch file in the list. */ + for (linked_list *patch = patch_list; patch != NULL; patch = patch->prev, --num_patches) { + const char *patch_file = (const char *)patch->data; + /* Create a new entry in the list. */ + pr->patches[num_patches] = create_file(root, patch_file); + } + + cleanup_linked_list(patch_list); + } + } +} + +static void parse_comment_reply(void *ctx, void *ret, const keyword *key, keyword_val val) { + linked_list *comment_list = *(linked_list **)ctx; + comment *comment = (comment *)ret; + + /* Do we already have a reply? */ + if (comment->reply != NULL) { + /* Check if this reply matches any other comment in the list. */ + for (linked_list *node = get_tail(comment_list); node != NULL; node = node->prev) { + comment *reply = (comment *)node->data; + + /* Do we have a match? */ + if (comment->reply == reply) { + return; + } + } + } + + /* Do we have a "reply-to" keyword? */ + if (key->type == TYPE_INT) { + int found_reply = 0; + /* Check if that comment already exists in the list. */ + for (linked_list *node = get_tail(comment_list); node != NULL; node = node->prev) { + comment *reply = (comment *)node->data; + + /* Do we have a match? */ + if (reply->id == val.i) { + /* Does this comment already have a reply? */ + if (comment->reply != NULL) { + /* Free the reply. */ + free(comment->reply); + } + + /* Set our reply comment to the matched comment. */ + comment->reply = reply; + found_reply = 1; + break; + } + } + + /* Did we find a reply in the list? */ + if (found_reply) { + return; + } + } + + /* Do we not have a reply? */ + if (comment->reply == NULL) { + /* Create one. */ + comment->reply = calloc(1, sizeof(comment)); + } + /* Which keyword do we have? */ + switch (key->type) { + /* reply-to */ + case TYPE_INT : comment->reply->id = val.i; break; + /* reply-author */ + case TYPE_STRING: comment->reply->author = val.str; break; + /* reply-date */ + case TYPE_TIME : comment->reply->date = val.t; break; + default : break; + } +} + +typedef int (parse_callback)(void **ret, void *ctx, char *buf); + +static int parse_colon_key_value_file(void *ret, void *ctx, const keyword **keywords, char *buf, parse_callback *parse_cb) { + if (buf != NULL) { + int ret = 0; + for (;;) { + char *lhs, *rhs; + /* Find the keyword before the colon. */ + lhs = strtok_r(skip_whitespace(buf), ":", &buf); + /* Remove any whitespace ahead of us. */ + lhs = strtok_r(lhs, " \t\v\r\n", &rhs); + + /* Did we hit EOF? */ + if (lhs == NULL) { + break; + } else { + char *tmp = skip_whitespace(buf); + + /* Does the right hand side start with a double, or single quote? */ + if (*tmp == '\"' || *tmp == '\'') { + const char *delm = (delm == '\"') ? "\"" : "\'"; + /* Get the string in between the start, and end qoute. */ + rhs = get_str_delm_range(tmp, delm, delm, &buf); + } else { + /* Get the rest of the line. */ + rhs = strtok_r(tmp, "\n", &buf); + } + + /* Did we fail to parse the keyword? */ + if (int error = parse_keywords(keywords, lhs, rhs, ret, ctx)) { + log(LOG_WARNING, "Failed to parse keyword \"%s\". Error code: %i", lhs, error); + ret = error; + } + } + + /* Do we have a parse callback? */ + if (parse_cb != NULL) { + /* Did the callback return an error. */ + if (parse_cb(&ret, ctx, buf) < 0) { + ret = 5; + break; + } + } + } + return ret; + } else { + return 6; + } +} + +static int is_end_of_comment(void **ret, void *ctx, char *buf) { + /* Do we have at least one blank line? */ + if (strspn(buf, "\n") >= 1) { + linked_list **comment_list = (linked_list **)ctx; + if (comment_list != NULL) { + /* Is our comment list NULL, or is there an existing entry? */ + if (*comment_list == NULL || (*comment_list)->data == NULL) { + add_node(comment_list, *ret); + } + *ret = calloc(1, sizeof(comment)); + return 1; + } else { + return -1; + } + } + return 0; +} + +static int parse_comments_file(comment ***comments, char *buf) { + if (comments == NULL) { + return 7; + } else { + linked_list *comment_list = NULL; + int ret = parse_colon_key_value_file(calloc(1, sizeof(comment)), &comment_list, comment_keywords, buf, is_end_of_comment); + *comments = linked_list_to_array(comment_list); + cleanup_linked_list(comments_list); + return ret; + } +} + + +static int parse_info_file(pull_request *pr, char *buf, const char *root) { + return parse_colon_key_value_file(pr, root, info_keywords, buf, NULL); +} + +static int parse_comments_file_path(comment ***comments, const char *root) { + file *f = create_file(root, "comments"); + int ret = parse_comments_file(comments, f->buf); + free_file(f); + return ret; +} + +static int parse_info_file_path(pull_request *pr, const char *root) { + file *f = create_file(root, "info"); + int ret = parse_info_file(pr, f->buf, root); + free_file(f); + return ret; +} + +pull_request *get_pull_request(index *idx, const char *root) { + /* Do we have a valid index? */ + if (is_valid_index(idx)) { + char *pr_dir; + char *idx_str = index_to_str(idx); + + /* Does the converted path of our index exist? */ + if (index_path_exists(idx, root, &pr_dir) >= 0) { + pull_request *pr = calloc(1, sizeof(pull_request)); + + log(LOG_NOTICE, "Found PR #%s with path \"%s\".", idx_str, pr_dir); + + /* Did we successfully parse the info file? */ + if (parse_info_file_path(pr, pr_dir) <= 1) { + log(LOG_NOTICE, "Successfully parsed info file of PR #%s.", idx_str); + + /* Did we successfully parse the comments file? */ + if (parse_comments_file_path(&pr->comments, pr_dir) <= 1) { + log(LOG_NOTICE, "Successfully parsed comments file of PR #%s.", idx_str); + } else { + log(LOG_WARNING, "Failed to parse comments file of PR #%s.", idx_str); + } + + return pr; + } else { + log(LOG_ERR, "Failed to parse info file of PR #%s.", idx_str); + free(pr); + return NULL; + } + } else { + log(LOG_ERR, "No PR #%s found.", idx_str); + free(idx_str); + return NULL; + } + } else { + return NULL; + } } int get_info_len(pull_request *pr) { |