blob: 93b4767ee57f2c7d66a01a0daf718d366d204b1a [file] [log] [blame]
Jason A. Donenfeldd01a6ee2014-01-10 04:59:34 +01001/* parsing.c: parsing of config files
Lars Hjemli7640d902006-12-10 22:41:14 +01002 *
Lukas Fleischerf7f26f82014-01-08 15:10:49 +01003 * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
Lars Hjemli7640d902006-12-10 22:41:14 +01004 *
5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text)
7 */
8
Lars Hjemli0d169ad2006-12-09 15:18:17 +01009#include "cgit.h"
10
Lars Hjemli30ccdca2007-05-18 03:00:54 +020011/*
12 * url syntax: [repo ['/' cmd [ '/' path]]]
13 * repo: any valid repo url, may contain '/'
14 * cmd: log | commit | diff | tree | view | blob | snapshot
15 * path: any valid path, may contain '/'
16 *
17 */
18void cgit_parse_url(const char *url)
19{
Julian Maurice10451792014-03-28 23:18:29 +010020 char *c, *cmd, *p;
21 struct cgit_repo *repo;
Lars Hjemli30ccdca2007-05-18 03:00:54 +020022
Lars Hjemli30ccdca2007-05-18 03:00:54 +020023 if (!url || url[0] == '\0')
24 return;
25
John Keeping9d751e72017-10-14 13:02:53 +010026 ctx.qry.page = NULL;
Lars Hjemlid1f3bbe2008-02-16 13:56:09 +010027 ctx.repo = cgit_get_repoinfo(url);
28 if (ctx.repo) {
29 ctx.qry.repo = ctx.repo->url;
Lars Hjemli30ccdca2007-05-18 03:00:54 +020030 return;
31 }
32
Julian Maurice10451792014-03-28 23:18:29 +010033 cmd = NULL;
34 c = strchr(url, '/');
35 while (c) {
36 c[0] = '\0';
37 repo = cgit_get_repoinfo(url);
38 if (repo) {
39 ctx.repo = repo;
40 cmd = c;
Lars Hjemli30ccdca2007-05-18 03:00:54 +020041 }
Julian Maurice10451792014-03-28 23:18:29 +010042 c[0] = '/';
43 c = strchr(c + 1, '/');
44 }
Lars Hjemli30ccdca2007-05-18 03:00:54 +020045
Julian Maurice10451792014-03-28 23:18:29 +010046 if (ctx.repo) {
Lars Hjemlid1f3bbe2008-02-16 13:56:09 +010047 ctx.qry.repo = ctx.repo->url;
Lars Hjemli30ccdca2007-05-18 03:00:54 +020048 p = strchr(cmd + 1, '/');
49 if (p) {
50 p[0] = '\0';
Lars Hjemli3de63b22007-05-18 13:06:45 +020051 if (p[1])
Lars Hjemlid14d77f2008-02-16 11:53:40 +010052 ctx.qry.path = trim_end(p + 1, '/');
Lars Hjemli30ccdca2007-05-18 03:00:54 +020053 }
Lars Hjemlie0e44782008-03-24 01:09:39 +010054 if (cmd[1])
55 ctx.qry.page = xstrdup(cmd + 1);
Lars Hjemli30ccdca2007-05-18 03:00:54 +020056 }
57}
58
Lukas Fleischerbafab422013-03-04 08:52:33 +010059static char *substr(const char *head, const char *tail)
Lars Hjemli2101e262006-12-15 18:17:36 +010060{
61 char *buf;
62
Jim Meyering61d41472012-04-23 22:06:35 +020063 if (tail < head)
64 return xstrdup("");
Lars Hjemli2101e262006-12-15 18:17:36 +010065 buf = xmalloc(tail - head + 1);
Christian Hesse7cde5882018-08-28 18:11:50 +020066 strlcpy(buf, head, tail - head + 1);
Lars Hjemli2101e262006-12-15 18:17:36 +010067 return buf;
68}
69
John Keeping45c87ca2016-01-19 19:33:02 +000070static void parse_user(const char *t, char **name, char **email, unsigned long *date, int *tz)
Lars Hjemlia8305a92008-09-14 09:45:37 +020071{
Lukas Fleischer6f9e8a92014-12-24 08:50:11 +010072 struct ident_split ident;
73 unsigned email_len;
Lars Hjemlia8305a92008-09-14 09:45:37 +020074
Lukas Fleischer3cb8e762015-03-05 12:58:12 +010075 if (!split_ident_line(&ident, t, strchrnul(t, '\n') - t)) {
Lukas Fleischer6f9e8a92014-12-24 08:50:11 +010076 *name = substr(ident.name_begin, ident.name_end);
77
78 email_len = ident.mail_end - ident.mail_begin;
79 *email = xmalloc(strlen("<") + email_len + strlen(">") + 1);
Christian Hesse60a93002018-08-28 18:14:32 +020080 xsnprintf(*email, email_len + 3, "<%.*s>", email_len, ident.mail_begin);
Lukas Fleischer6f9e8a92014-12-24 08:50:11 +010081
82 if (ident.date_begin)
83 *date = strtoul(ident.date_begin, NULL, 10);
John Keeping45c87ca2016-01-19 19:33:02 +000084 if (ident.tz_begin)
85 *tz = atoi(ident.tz_begin);
Lars Hjemlia8305a92008-09-14 09:45:37 +020086 }
Lars Hjemlia8305a92008-09-14 09:45:37 +020087}
88
Lars Hjemli14b4e102008-12-05 19:10:28 +010089#ifdef NO_ICONV
90#define reencode(a, b, c)
91#else
Lukas Fleischerbafab422013-03-04 08:52:33 +010092static const char *reencode(char **txt, const char *src_enc, const char *dst_enc)
Lars Hjemlia8305a92008-09-14 09:45:37 +020093{
94 char *tmp;
95
Lukas Fleischera0bf3752011-04-05 10:35:43 +020096 if (!txt)
97 return NULL;
98
99 if (!*txt || !src_enc || !dst_enc)
Lars Hjemlia8305a92008-09-14 09:45:37 +0200100 return *txt;
101
Julius Plenz0a799422011-03-10 17:03:23 +0100102 /* no encoding needed if src_enc equals dst_enc */
Jason A. Donenfeldbdae1d82013-03-03 23:21:33 -0500103 if (!strcasecmp(src_enc, dst_enc))
Julius Plenz0a799422011-03-10 17:03:23 +0100104 return *txt;
105
106 tmp = reencode_string(*txt, dst_enc, src_enc);
Lars Hjemlia8305a92008-09-14 09:45:37 +0200107 if (tmp) {
108 free(*txt);
109 *txt = tmp;
110 }
111 return *txt;
112}
Lars Hjemli14b4e102008-12-05 19:10:28 +0100113#endif
Lars Hjemlia8305a92008-09-14 09:45:37 +0200114
Lukas Fleischer936295c2015-03-03 13:00:07 +0100115static const char *next_header_line(const char *p)
116{
117 p = strchr(p, '\n');
118 if (!p)
119 return NULL;
120 return p + 1;
121}
122
123static int end_of_header(const char *p)
124{
125 return !p || (*p == '\n');
126}
127
Lars Hjemli2101e262006-12-15 18:17:36 +0100128struct commitinfo *cgit_parse_commit(struct commit *commit)
129{
Lukas Fleischer936295c2015-03-03 13:00:07 +0100130 const int sha1hex_len = 40;
Lars Hjemli2101e262006-12-15 18:17:36 +0100131 struct commitinfo *ret;
Christian Hessebfabd452019-10-23 23:21:54 +0200132 const char *p = repo_get_commit_buffer(the_repository, commit, NULL);
John Keeping865afe02014-07-27 11:56:19 +0100133 const char *t;
Lars Hjemli2101e262006-12-15 18:17:36 +0100134
Lukas Fleischer936295c2015-03-03 13:00:07 +0100135 ret = xcalloc(1, sizeof(struct commitinfo));
Lars Hjemli2101e262006-12-15 18:17:36 +0100136 ret->commit = commit;
137
Lukas Fleischer936295c2015-03-03 13:00:07 +0100138 if (!p)
Ondrej Jirman61302312007-05-26 03:27:49 +0200139 return ret;
140
Lukas Fleischer936295c2015-03-03 13:00:07 +0100141 if (!skip_prefix(p, "tree ", &p))
Christian Hesse559ab5e2016-01-05 07:38:53 +0100142 die("Bad commit: %s", oid_to_hex(&commit->object.oid));
Lukas Fleischer936295c2015-03-03 13:00:07 +0100143 p += sha1hex_len + 1;
Lars Hjemli2101e262006-12-15 18:17:36 +0100144
Lukas Fleischer936295c2015-03-03 13:00:07 +0100145 while (skip_prefix(p, "parent ", &p))
146 p += sha1hex_len + 1;
Lars Hjemli2101e262006-12-15 18:17:36 +0100147
Lukas Fleischer936295c2015-03-03 13:00:07 +0100148 if (p && skip_prefix(p, "author ", &p)) {
Lukas Fleischer3cb8e762015-03-05 12:58:12 +0100149 parse_user(p, &ret->author, &ret->author_email,
John Keeping45c87ca2016-01-19 19:33:02 +0000150 &ret->author_date, &ret->author_tz);
Lukas Fleischer3cb8e762015-03-05 12:58:12 +0100151 p = next_header_line(p);
Lars Hjemli2101e262006-12-15 18:17:36 +0100152 }
153
Lukas Fleischer936295c2015-03-03 13:00:07 +0100154 if (p && skip_prefix(p, "committer ", &p)) {
Lukas Fleischer3cb8e762015-03-05 12:58:12 +0100155 parse_user(p, &ret->committer, &ret->committer_email,
John Keeping45c87ca2016-01-19 19:33:02 +0000156 &ret->committer_date, &ret->committer_tz);
Lukas Fleischer3cb8e762015-03-05 12:58:12 +0100157 p = next_header_line(p);
Lars Hjemli2101e262006-12-15 18:17:36 +0100158 }
159
Lukas Fleischer936295c2015-03-03 13:00:07 +0100160 if (p && skip_prefix(p, "encoding ", &p)) {
Lars Hjemlia8305a92008-09-14 09:45:37 +0200161 t = strchr(p, '\n');
162 if (t) {
163 ret->msg_encoding = substr(p, t + 1);
164 p = t + 1;
165 }
166 }
Jonathan Bastien-Filiatraultaa5cc322007-10-26 18:10:26 -0400167
Jason A. Donenfeldbdae1d82013-03-03 23:21:33 -0500168 if (!ret->msg_encoding)
Julius Plenz0a799422011-03-10 17:03:23 +0100169 ret->msg_encoding = xstrdup("UTF-8");
170
Lukas Fleischer936295c2015-03-03 13:00:07 +0100171 while (!end_of_header(p))
172 p = next_header_line(p);
Lars Hjemlia8305a92008-09-14 09:45:37 +0200173 while (p && *p == '\n')
174 p++;
Lars Hjemlia8305a92008-09-14 09:45:37 +0200175 if (!p)
176 return ret;
Lars Hjemli2101e262006-12-15 18:17:36 +0100177
Lukas Fleischer936295c2015-03-03 13:00:07 +0100178 t = strchrnul(p, '\n');
179 ret->subject = substr(p, t);
180 while (*t == '\n')
181 t++;
182 ret->msg = xstrdup(t);
Ondrej Jirman3ce6fc12007-05-26 02:19:38 +0200183
Julius Plenz0a799422011-03-10 17:03:23 +0100184 reencode(&ret->author, ret->msg_encoding, PAGE_ENCODING);
185 reencode(&ret->author_email, ret->msg_encoding, PAGE_ENCODING);
186 reencode(&ret->committer, ret->msg_encoding, PAGE_ENCODING);
187 reencode(&ret->committer_email, ret->msg_encoding, PAGE_ENCODING);
188 reencode(&ret->subject, ret->msg_encoding, PAGE_ENCODING);
189 reencode(&ret->msg, ret->msg_encoding, PAGE_ENCODING);
Jonathan Bastien-Filiatrault7858a302007-10-26 18:13:41 -0400190
Lars Hjemli2101e262006-12-15 18:17:36 +0100191 return ret;
192}
Lars Hjemlia69061f2007-01-17 01:09:51 +0100193
Lars Hjemlia69061f2007-01-17 01:09:51 +0100194struct taginfo *cgit_parse_tag(struct tag *tag)
195{
196 void *data;
Lars Hjemli61c3ca92007-05-08 22:40:59 +0200197 enum object_type type;
Lars Hjemlia69061f2007-01-17 01:09:51 +0100198 unsigned long size;
John Keeping93d8ef82014-07-27 11:56:18 +0100199 const char *p;
Lukas Fleischer936295c2015-03-03 13:00:07 +0100200 struct taginfo *ret = NULL;
Lars Hjemlia69061f2007-01-17 01:09:51 +0100201
Christian Hesse255b78f2018-06-04 18:49:28 +0200202 data = read_object_file(&tag->object.oid, &type, &size);
Lukas Fleischer936295c2015-03-03 13:00:07 +0100203 if (!data || type != OBJ_TAG)
204 goto cleanup;
Lars Hjemli47a81c72007-05-15 23:28:40 +0200205
Lukas Fleischer936295c2015-03-03 13:00:07 +0100206 ret = xcalloc(1, sizeof(struct taginfo));
Lars Hjemlia69061f2007-01-17 01:09:51 +0100207
Lukas Fleischer936295c2015-03-03 13:00:07 +0100208 for (p = data; !end_of_header(p); p = next_header_line(p)) {
209 if (skip_prefix(p, "tagger ", &p)) {
Lukas Fleischer3cb8e762015-03-05 12:58:12 +0100210 parse_user(p, &ret->tagger, &ret->tagger_email,
John Keeping45c87ca2016-01-19 19:33:02 +0000211 &ret->tagger_date, &ret->tagger_tz);
Lars Hjemlia69061f2007-01-17 01:09:51 +0100212 }
Lars Hjemlia69061f2007-01-17 01:09:51 +0100213 }
214
Lukas Fleischer4d8ed332015-03-05 12:58:11 +0100215 while (p && *p == '\n')
216 p++;
217
Lars Hjemliebd7b0f2007-02-03 16:11:41 +0100218 if (p && *p)
Lars Hjemlia69061f2007-01-17 01:09:51 +0100219 ret->msg = xstrdup(p);
Lukas Fleischer936295c2015-03-03 13:00:07 +0100220
221cleanup:
Lars Hjemlia69061f2007-01-17 01:09:51 +0100222 free(data);
223 return ret;
224}