use less memory allocations when formatting log messages Rewrite got_object_commit_get_logmsg() such that only one memory allocation is made when creating a pretty version of a log message. ok naddy@
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
diff --git a/lib/object_parse.c b/lib/object_parse.c
index 011bee1..4c0fd4f 100644
--- a/lib/object_parse.c
+++ b/lib/object_parse.c
@@ -439,55 +439,48 @@ const struct got_error *
got_object_commit_get_logmsg(char **logmsg, struct got_commit_object *commit)
{
const struct got_error *err = NULL;
- char *msg0, *msg, *line, *s;
+ const char *src;
+ char *dst;
size_t len;
- int headers = 1;
- *logmsg = NULL;
-
- msg0 = strdup(commit->logmsg);
- if (msg0 == NULL)
- return got_error_from_errno("strdup");
-
- /* Copy log message line by line to strip out unusual headers... */
- msg = msg0;
- do {
- if ((line = strsep(&msg, "\n")) == NULL)
- break;
-
- if (headers == 1) {
- if (line[0] != '\0' &&
- strncmp(line, GOT_COMMIT_LABEL_TREE,
- strlen(GOT_COMMIT_LABEL_TREE)) != 0 &&
- strncmp(line, GOT_COMMIT_LABEL_AUTHOR,
- strlen(GOT_COMMIT_LABEL_AUTHOR)) != 0 &&
- strncmp(line, GOT_COMMIT_LABEL_PARENT,
- strlen(GOT_COMMIT_LABEL_PARENT)) != 0 &&
- strncmp(line, GOT_COMMIT_LABEL_COMMITTER,
- strlen(GOT_COMMIT_LABEL_COMMITTER)) != 0)
- continue;
-
- if (line[0] == '\0')
- headers = 0;
- }
+ len = strlen(commit->logmsg);
+ *logmsg = malloc(len + 2); /* leave room for a trailing \n and \0 */
+ if (*logmsg == NULL)
+ return got_error_from_errno("malloc");
- if (asprintf(&s, "%s%s\n",
- *logmsg ? *logmsg : "", line) == -1) {
- err = got_error_from_errno("asprintf");
- goto done;
+ /*
+ * Strip out unusual headers. Headers are separated from the commit
+ * message body by a single empty line.
+ */
+ src = commit->logmsg;
+ dst = *logmsg;
+ while (*src != '\0' && *src != '\n') {
+ int copy_header = 1, eol = 0;
+ if (strncmp(src, GOT_COMMIT_LABEL_TREE,
+ strlen(GOT_COMMIT_LABEL_TREE)) != 0 &&
+ strncmp(src, GOT_COMMIT_LABEL_AUTHOR,
+ strlen(GOT_COMMIT_LABEL_AUTHOR)) != 0 &&
+ strncmp(src, GOT_COMMIT_LABEL_PARENT,
+ strlen(GOT_COMMIT_LABEL_PARENT)) != 0 &&
+ strncmp(src, GOT_COMMIT_LABEL_COMMITTER,
+ strlen(GOT_COMMIT_LABEL_COMMITTER)) != 0)
+ copy_header = 0;
+
+ while (*src != '\0' && !eol) {
+ if (copy_header) {
+ *dst = *src;
+ dst++;
+ }
+ if (*src == '\n')
+ eol = 1;
+ src++;
}
- free(*logmsg);
- *logmsg = s;
-
- } while (line);
+ }
+ *dst = '\0';
- if (*logmsg == NULL) {
- /* log message does not contain \n */
- *logmsg = strdup(commit->logmsg);
- if (*logmsg == NULL) {
- err = got_error_from_errno("strdup");
- goto done;
- }
+ if (strlcat(*logmsg, src, len + 1) >= len + 1) {
+ err = got_error(GOT_ERR_NO_SPACE);
+ goto done;
}
/* Trim redundant trailing whitespace. */
@@ -497,8 +490,13 @@ got_object_commit_get_logmsg(char **logmsg, struct got_commit_object *commit)
(*logmsg)[len - 1] = '\0';
len--;
}
+
+ /* Append a trailing newline if missing. */
+ if (len > 0 && (*logmsg)[len - 1] != '\n') {
+ (*logmsg)[len] = '\n';
+ (*logmsg)[len + 1] = '\0';
+ }
done:
- free(msg0);
if (err) {
free(*logmsg);
*logmsg = NULL;