blob: 658621d8e76b74336eb8827b3354d59ec9d35320 [file] [log] [blame]
Lars Hjemli7640d902006-12-10 22:41:14 +01001/* config.c: parsing of config files
2 *
3 * Copyright (C) 2006 Lars Hjemli
4 *
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{
20 char *cmd, *p;
21
Lars Hjemlid1f3bbe2008-02-16 13:56:09 +010022 ctx.repo = NULL;
Lars Hjemli30ccdca2007-05-18 03:00:54 +020023 if (!url || url[0] == '\0')
24 return;
25
Lars Hjemlid1f3bbe2008-02-16 13:56:09 +010026 ctx.repo = cgit_get_repoinfo(url);
27 if (ctx.repo) {
28 ctx.qry.repo = ctx.repo->url;
Lars Hjemli30ccdca2007-05-18 03:00:54 +020029 return;
30 }
31
32 cmd = strchr(url, '/');
Lars Hjemlid1f3bbe2008-02-16 13:56:09 +010033 while (!ctx.repo && cmd) {
Lars Hjemli30ccdca2007-05-18 03:00:54 +020034 cmd[0] = '\0';
Lars Hjemlid1f3bbe2008-02-16 13:56:09 +010035 ctx.repo = cgit_get_repoinfo(url);
36 if (ctx.repo == NULL) {
Lars Hjemli30ccdca2007-05-18 03:00:54 +020037 cmd[0] = '/';
38 cmd = strchr(cmd + 1, '/');
39 continue;
40 }
41
Lars Hjemlid1f3bbe2008-02-16 13:56:09 +010042 ctx.qry.repo = ctx.repo->url;
Lars Hjemli30ccdca2007-05-18 03:00:54 +020043 p = strchr(cmd + 1, '/');
44 if (p) {
45 p[0] = '\0';
Lars Hjemli3de63b22007-05-18 13:06:45 +020046 if (p[1])
Lars Hjemlid14d77f2008-02-16 11:53:40 +010047 ctx.qry.path = trim_end(p + 1, '/');
Lars Hjemli30ccdca2007-05-18 03:00:54 +020048 }
Lars Hjemlie0e44782008-03-24 01:09:39 +010049 if (cmd[1])
50 ctx.qry.page = xstrdup(cmd + 1);
Lars Hjemli30ccdca2007-05-18 03:00:54 +020051 return;
52 }
53}
54
Lukas Fleischerbafab422013-03-04 08:52:33 +010055static char *substr(const char *head, const char *tail)
Lars Hjemli2101e262006-12-15 18:17:36 +010056{
57 char *buf;
58
Jim Meyering61d41472012-04-23 22:06:35 +020059 if (tail < head)
60 return xstrdup("");
Lars Hjemli2101e262006-12-15 18:17:36 +010061 buf = xmalloc(tail - head + 1);
62 strncpy(buf, head, tail - head);
63 buf[tail - head] = '\0';
64 return buf;
65}
66
Lukas Fleischerbafab422013-03-04 08:52:33 +010067static char *parse_user(char *t, char **name, char **email, unsigned long *date)
Lars Hjemlia8305a92008-09-14 09:45:37 +020068{
69 char *p = t;
70 int mode = 1;
71
72 while (p && *p) {
73 if (mode == 1 && *p == '<') {
74 *name = substr(t, p - 1);
75 t = p;
76 mode++;
77 } else if (mode == 1 && *p == '\n') {
78 *name = substr(t, p);
79 p++;
80 break;
81 } else if (mode == 2 && *p == '>') {
82 *email = substr(t, p + 1);
83 t = p;
84 mode++;
85 } else if (mode == 2 && *p == '\n') {
86 *email = substr(t, p);
87 p++;
88 break;
89 } else if (mode == 3 && isdigit(*p)) {
90 *date = atol(p);
91 mode++;
92 } else if (*p == '\n') {
93 p++;
94 break;
95 }
96 p++;
97 }
98 return p;
99}
100
Lars Hjemli14b4e102008-12-05 19:10:28 +0100101#ifdef NO_ICONV
102#define reencode(a, b, c)
103#else
Lukas Fleischerbafab422013-03-04 08:52:33 +0100104static const char *reencode(char **txt, const char *src_enc, const char *dst_enc)
Lars Hjemlia8305a92008-09-14 09:45:37 +0200105{
106 char *tmp;
107
Lukas Fleischera0bf3752011-04-05 10:35:43 +0200108 if (!txt)
109 return NULL;
110
111 if (!*txt || !src_enc || !dst_enc)
Lars Hjemlia8305a92008-09-14 09:45:37 +0200112 return *txt;
113
Julius Plenz0a799422011-03-10 17:03:23 +0100114 /* no encoding needed if src_enc equals dst_enc */
Jason A. Donenfeldbdae1d82013-03-03 23:21:33 -0500115 if (!strcasecmp(src_enc, dst_enc))
Julius Plenz0a799422011-03-10 17:03:23 +0100116 return *txt;
117
118 tmp = reencode_string(*txt, dst_enc, src_enc);
Lars Hjemlia8305a92008-09-14 09:45:37 +0200119 if (tmp) {
120 free(*txt);
121 *txt = tmp;
122 }
123 return *txt;
124}
Lars Hjemli14b4e102008-12-05 19:10:28 +0100125#endif
Lars Hjemlia8305a92008-09-14 09:45:37 +0200126
Lars Hjemli2101e262006-12-15 18:17:36 +0100127struct commitinfo *cgit_parse_commit(struct commit *commit)
128{
129 struct commitinfo *ret;
Lukas Fleischer1e25ac52011-07-21 23:04:53 +0200130 char *p = commit->buffer, *t;
Lars Hjemli2101e262006-12-15 18:17:36 +0100131
132 ret = xmalloc(sizeof(*ret));
133 ret->commit = commit;
Lars Hjemli66091f92007-01-16 18:41:01 +0100134 ret->author = NULL;
135 ret->author_email = NULL;
136 ret->committer = NULL;
137 ret->committer_email = NULL;
138 ret->subject = NULL;
139 ret->msg = NULL;
Jonathan Bastien-Filiatrault3845e172007-10-26 18:09:06 -0400140 ret->msg_encoding = NULL;
Lars Hjemli2101e262006-12-15 18:17:36 +0100141
Ondrej Jirman61302312007-05-26 03:27:49 +0200142 if (p == NULL)
143 return ret;
144
Lars Hjemli2101e262006-12-15 18:17:36 +0100145 if (strncmp(p, "tree ", 5))
146 die("Bad commit: %s", sha1_to_hex(commit->object.sha1));
147 else
148 p += 46; // "tree " + hex[40] + "\n"
149
150 while (!strncmp(p, "parent ", 7))
151 p += 48; // "parent " + hex[40] + "\n"
152
Lars Hjemlia8305a92008-09-14 09:45:37 +0200153 if (p && !strncmp(p, "author ", 7)) {
154 p = parse_user(p + 7, &ret->author, &ret->author_email,
155 &ret->author_date);
Lars Hjemli2101e262006-12-15 18:17:36 +0100156 }
157
Lars Hjemlia8305a92008-09-14 09:45:37 +0200158 if (p && !strncmp(p, "committer ", 9)) {
159 p = parse_user(p + 9, &ret->committer, &ret->committer_email,
160 &ret->committer_date);
Lars Hjemli2101e262006-12-15 18:17:36 +0100161 }
162
Lars Hjemlia8305a92008-09-14 09:45:37 +0200163 if (p && !strncmp(p, "encoding ", 9)) {
Jonathan Bastien-Filiatraultaa5cc322007-10-26 18:10:26 -0400164 p += 9;
Lars Hjemlia8305a92008-09-14 09:45:37 +0200165 t = strchr(p, '\n');
166 if (t) {
167 ret->msg_encoding = substr(p, t + 1);
168 p = t + 1;
169 }
170 }
Jonathan Bastien-Filiatraultaa5cc322007-10-26 18:10:26 -0400171
Julius Plenz0a799422011-03-10 17:03:23 +0100172 /* if no special encoding is found, assume UTF-8 */
Jason A. Donenfeldbdae1d82013-03-03 23:21:33 -0500173 if (!ret->msg_encoding)
Julius Plenz0a799422011-03-10 17:03:23 +0100174 ret->msg_encoding = xstrdup("UTF-8");
175
Lars Hjemlia8305a92008-09-14 09:45:37 +0200176 // skip unknown header fields
177 while (p && *p && (*p != '\n')) {
178 p = strchr(p, '\n');
179 if (p)
180 p++;
181 }
Lars Hjemli13d2b0b2007-10-24 21:14:44 +0200182
Lars Hjemlia8305a92008-09-14 09:45:37 +0200183 // skip empty lines between headers and message
184 while (p && *p == '\n')
185 p++;
186
187 if (!p)
188 return ret;
Lars Hjemli2101e262006-12-15 18:17:36 +0100189
190 t = strchr(p, '\n');
Ondrej Jirman3ce6fc12007-05-26 02:19:38 +0200191 if (t) {
Lars Hjemlia8305a92008-09-14 09:45:37 +0200192 ret->subject = substr(p, t);
Lars Hjemli66091f92007-01-16 18:41:01 +0100193 p = t + 1;
Lars Hjemli2101e262006-12-15 18:17:36 +0100194
Lars Hjemlia8305a92008-09-14 09:45:37 +0200195 while (p && *p == '\n') {
196 p = strchr(p, '\n');
197 if (p)
198 p++;
199 }
200 if (p)
201 ret->msg = xstrdup(p);
Ondrej Jirman3ce6fc12007-05-26 02:19:38 +0200202 } else
Lars Hjemlia8305a92008-09-14 09:45:37 +0200203 ret->subject = xstrdup(p);
Ondrej Jirman3ce6fc12007-05-26 02:19:38 +0200204
Julius Plenz0a799422011-03-10 17:03:23 +0100205 reencode(&ret->author, ret->msg_encoding, PAGE_ENCODING);
206 reencode(&ret->author_email, ret->msg_encoding, PAGE_ENCODING);
207 reencode(&ret->committer, ret->msg_encoding, PAGE_ENCODING);
208 reencode(&ret->committer_email, ret->msg_encoding, PAGE_ENCODING);
209 reencode(&ret->subject, ret->msg_encoding, PAGE_ENCODING);
210 reencode(&ret->msg, ret->msg_encoding, PAGE_ENCODING);
Jonathan Bastien-Filiatrault7858a302007-10-26 18:13:41 -0400211
Lars Hjemli2101e262006-12-15 18:17:36 +0100212 return ret;
213}
Lars Hjemlia69061f2007-01-17 01:09:51 +0100214
215
216struct taginfo *cgit_parse_tag(struct tag *tag)
217{
218 void *data;
Lars Hjemli61c3ca92007-05-08 22:40:59 +0200219 enum object_type type;
Lars Hjemlia69061f2007-01-17 01:09:51 +0100220 unsigned long size;
Lars Hjemlia8305a92008-09-14 09:45:37 +0200221 char *p;
Lars Hjemlia69061f2007-01-17 01:09:51 +0100222 struct taginfo *ret;
223
Lars Hjemli61c3ca92007-05-08 22:40:59 +0200224 data = read_sha1_file(tag->object.sha1, &type, &size);
225 if (!data || type != OBJ_TAG) {
Lars Hjemlia69061f2007-01-17 01:09:51 +0100226 free(data);
227 return 0;
228 }
Lars Hjemli47a81c72007-05-15 23:28:40 +0200229
Lars Hjemlia69061f2007-01-17 01:09:51 +0100230 ret = xmalloc(sizeof(*ret));
231 ret->tagger = NULL;
232 ret->tagger_email = NULL;
233 ret->tagger_date = 0;
234 ret->msg = NULL;
235
236 p = data;
237
Lars Hjemliebd7b0f2007-02-03 16:11:41 +0100238 while (p && *p) {
Lars Hjemlia69061f2007-01-17 01:09:51 +0100239 if (*p == '\n')
240 break;
241
242 if (!strncmp(p, "tagger ", 7)) {
Lars Hjemlia8305a92008-09-14 09:45:37 +0200243 p = parse_user(p + 7, &ret->tagger, &ret->tagger_email,
244 &ret->tagger_date);
245 } else {
246 p = strchr(p, '\n');
247 if (p)
248 p++;
Lars Hjemlia69061f2007-01-17 01:09:51 +0100249 }
Lars Hjemlia69061f2007-01-17 01:09:51 +0100250 }
251
Lars Hjemlia8305a92008-09-14 09:45:37 +0200252 // skip empty lines between headers and message
253 while (p && *p == '\n')
254 p++;
Lars Hjemli13d2b0b2007-10-24 21:14:44 +0200255
Lars Hjemliebd7b0f2007-02-03 16:11:41 +0100256 if (p && *p)
Lars Hjemlia69061f2007-01-17 01:09:51 +0100257 ret->msg = xstrdup(p);
258 free(data);
259 return ret;
260}