all repos — cgit @ 20a33548b9a87a6eb23162ee5d137daa46d78613

a hyperfast web frontend for git written in c

parsing.c (view raw)

  1/* 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
  9#include "cgit.h"
 10
 11char *convert_query_hexchar(char *txt)
 12{
 13	int d1, d2;
 14	if (strlen(txt) < 3) {
 15		*txt = '\0';
 16		return txt-1;
 17	}
 18	d1 = hextoint(*(txt+1));
 19	d2 = hextoint(*(txt+2));
 20	if (d1<0 || d2<0) {
 21		strcpy(txt, txt+3);
 22		return txt-1;
 23	} else {
 24		*txt = d1 * 16 + d2;
 25		strcpy(txt+1, txt+3);
 26		return txt;
 27	}
 28}
 29
 30int cgit_parse_query(char *txt, configfn fn)
 31{
 32	char *t, *value = NULL, c;
 33
 34	if (!txt)
 35		return 0;
 36
 37	t = txt = xstrdup(txt);
 38
 39	while((c=*t) != '\0') {
 40		if (c=='=') {
 41			*t = '\0';
 42			value = t+1;
 43		} else if (c=='+') {
 44			*t = ' ';
 45		} else if (c=='%') {
 46			t = convert_query_hexchar(t);
 47		} else if (c=='&') {
 48			*t = '\0';
 49			(*fn)(txt, value);
 50			txt = t+1;
 51			value = NULL;
 52		}
 53		t++;
 54	}
 55	if (t!=txt)
 56		(*fn)(txt, value);
 57	return 0;
 58}
 59
 60/*
 61 * url syntax: [repo ['/' cmd [ '/' path]]]
 62 *   repo: any valid repo url, may contain '/'
 63 *   cmd:  log | commit | diff | tree | view | blob | snapshot
 64 *   path: any valid path, may contain '/'
 65 *
 66 */
 67void cgit_parse_url(const char *url)
 68{
 69	char *cmd, *p;
 70
 71	ctx.repo = NULL;
 72	if (!url || url[0] == '\0')
 73		return;
 74
 75	ctx.repo = cgit_get_repoinfo(url);
 76	if (ctx.repo) {
 77		ctx.qry.repo = ctx.repo->url;
 78		return;
 79	}
 80
 81	cmd = strchr(url, '/');
 82	while (!ctx.repo && cmd) {
 83		cmd[0] = '\0';
 84		ctx.repo = cgit_get_repoinfo(url);
 85		if (ctx.repo == NULL) {
 86			cmd[0] = '/';
 87			cmd = strchr(cmd + 1, '/');
 88			continue;
 89		}
 90
 91		ctx.qry.repo = ctx.repo->url;
 92		p = strchr(cmd + 1, '/');
 93		if (p) {
 94			p[0] = '\0';
 95			if (p[1])
 96				ctx.qry.path = trim_end(p + 1, '/');
 97		}
 98		if (cmd[1])
 99			ctx.qry.page = xstrdup(cmd + 1);
100		return;
101	}
102}
103
104char *substr(const char *head, const char *tail)
105{
106	char *buf;
107
108	buf = xmalloc(tail - head + 1);
109	strncpy(buf, head, tail - head);
110	buf[tail - head] = '\0';
111	return buf;
112}
113
114struct commitinfo *cgit_parse_commit(struct commit *commit)
115{
116	struct commitinfo *ret;
117	char *p = commit->buffer, *t = commit->buffer;
118
119	ret = xmalloc(sizeof(*ret));
120	ret->commit = commit;
121	ret->author = NULL;
122	ret->author_email = NULL;
123	ret->committer = NULL;
124	ret->committer_email = NULL;
125	ret->subject = NULL;
126	ret->msg = NULL;
127	ret->msg_encoding = NULL;
128
129	if (p == NULL)
130		return ret;
131
132	if (strncmp(p, "tree ", 5))
133		die("Bad commit: %s", sha1_to_hex(commit->object.sha1));
134	else
135		p += 46; // "tree " + hex[40] + "\n"
136
137	while (!strncmp(p, "parent ", 7))
138		p += 48; // "parent " + hex[40] + "\n"
139
140	if (!strncmp(p, "author ", 7)) {
141		p += 7;
142		t = strchr(p, '<') - 1;
143		ret->author = substr(p, t);
144		p = t;
145		t = strchr(t, '>') + 1;
146		ret->author_email = substr(p, t);
147		ret->author_date = atol(t+1);
148		p = strchr(t, '\n') + 1;
149	}
150
151	if (!strncmp(p, "committer ", 9)) {
152		p += 9;
153		t = strchr(p, '<') - 1;
154		ret->committer = substr(p, t);
155		p = t;
156		t = strchr(t, '>') + 1;
157		ret->committer_email = substr(p, t);
158		ret->committer_date = atol(t+1);
159		p = strchr(t, '\n') + 1;
160	}
161
162	if (!strncmp(p, "encoding ", 9)) {
163		p += 9;
164		t = strchr(p, '\n') + 1;
165		ret->msg_encoding = substr(p, t);
166		p = t;
167	} else
168		ret->msg_encoding = xstrdup(PAGE_ENCODING);
169
170	while (*p && (*p != '\n'))
171		p = strchr(p, '\n') + 1; // skip unknown header fields
172
173	while (*p == '\n')
174		p = strchr(p, '\n') + 1;
175
176	t = strchr(p, '\n');
177	if (t) {
178		if (*t == '\0')
179			ret->subject = "** empty **";
180		else
181			ret->subject = substr(p, t);
182		p = t + 1;
183
184		while (*p == '\n')
185			p = strchr(p, '\n') + 1;
186		ret->msg = xstrdup(p);
187	} else
188		ret->subject = substr(p, p+strlen(p));
189
190	if(strcmp(ret->msg_encoding, PAGE_ENCODING)) {
191		t = reencode_string(ret->subject, PAGE_ENCODING,
192				    ret->msg_encoding);
193		if(t) {
194			free(ret->subject);
195			ret->subject = t;
196		}
197
198		t = reencode_string(ret->msg, PAGE_ENCODING,
199				    ret->msg_encoding);
200		if(t) {
201			free(ret->msg);
202			ret->msg = t;
203		}
204	}
205
206	return ret;
207}
208
209
210struct taginfo *cgit_parse_tag(struct tag *tag)
211{
212	void *data;
213	enum object_type type;
214	unsigned long size;
215	char *p, *t;
216	struct taginfo *ret;
217
218	data = read_sha1_file(tag->object.sha1, &type, &size);
219	if (!data || type != OBJ_TAG) {
220		free(data);
221		return 0;
222	}
223
224	ret = xmalloc(sizeof(*ret));
225	ret->tagger = NULL;
226	ret->tagger_email = NULL;
227	ret->tagger_date = 0;
228	ret->msg = NULL;
229
230	p = data;
231
232	while (p && *p) {
233		if (*p == '\n')
234			break;
235
236		if (!strncmp(p, "tagger ", 7)) {
237			p += 7;
238			t = strchr(p, '<') - 1;
239			ret->tagger = substr(p, t);
240			p = t;
241			t = strchr(t, '>') + 1;
242			ret->tagger_email = substr(p, t);
243			ret->tagger_date = atol(t+1);
244		}
245		p = strchr(p, '\n') + 1;
246	}
247
248	while (p && *p && (*p != '\n'))
249		p = strchr(p, '\n') + 1; // skip unknown tag fields
250
251	while (p && (*p == '\n'))
252		p = strchr(p, '\n') + 1;
253	if (p && *p)
254		ret->msg = xstrdup(p);
255	free(data);
256	return ret;
257}