all repos — cgit @ 19134112bf942c0492f2095b668ea31c1a498f1a

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
 11int next_char(FILE *f)
 12{
 13	int c = fgetc(f);
 14	if (c=='\r') {
 15		c = fgetc(f);
 16		if (c!='\n') {
 17			ungetc(c, f);
 18			c = '\r';
 19		}
 20	}
 21	return c;
 22}
 23
 24void skip_line(FILE *f)
 25{
 26	int c;
 27
 28	while((c=next_char(f)) && c!='\n' && c!=EOF)
 29		;
 30}
 31
 32int read_config_line(FILE *f, char *line, const char **value, int bufsize)
 33{
 34	int i = 0, isname = 0;
 35
 36	*value = NULL;
 37	while(i<bufsize-1) {
 38		int c = next_char(f);
 39		if (!isname && (c=='#' || c==';')) {
 40			skip_line(f);
 41			continue;
 42		}
 43		if (!isname && isspace(c))
 44			continue;
 45
 46		if (c=='=' && !*value) {
 47			line[i] = 0;
 48			*value = &line[i+1];
 49		} else if (c=='\n' && !isname) {
 50			i = 0;
 51			continue;
 52		} else if (c=='\n' || c==EOF) {
 53			line[i] = 0;
 54			break;
 55		} else {
 56			line[i]=c;
 57		}
 58		isname = 1;
 59		i++;
 60	}
 61	line[i+1] = 0;
 62	return i;
 63}
 64
 65int cgit_read_config(const char *filename, configfn fn)
 66{
 67	static int nesting;
 68	int len;
 69	char line[256];
 70	const char *value;
 71	FILE *f;
 72
 73	/* cancel deeply nested include-commands */
 74	if (nesting > 8)
 75		return -1;
 76	if (!(f = fopen(filename, "r")))
 77		return -1;
 78	nesting++;
 79	while((len = read_config_line(f, line, &value, sizeof(line))) > 0)
 80		(*fn)(line, value);
 81	nesting--;
 82	fclose(f);
 83	return 0;
 84}
 85
 86char *convert_query_hexchar(char *txt)
 87{
 88	int d1, d2;
 89	if (strlen(txt) < 3) {
 90		*txt = '\0';
 91		return txt-1;
 92	}
 93	d1 = hextoint(*(txt+1));
 94	d2 = hextoint(*(txt+2));
 95	if (d1<0 || d2<0) {
 96		strcpy(txt, txt+3);
 97		return txt-1;
 98	} else {
 99		*txt = d1 * 16 + d2;
100		strcpy(txt+1, txt+3);
101		return txt;
102	}
103}
104
105int cgit_parse_query(char *txt, configfn fn)
106{
107	char *t, *value = NULL, c;
108
109	if (!txt)
110		return 0;
111
112	t = txt = xstrdup(txt);
113
114	while((c=*t) != '\0') {
115		if (c=='=') {
116			*t = '\0';
117			value = t+1;
118		} else if (c=='+') {
119			*t = ' ';
120		} else if (c=='%') {
121			t = convert_query_hexchar(t);
122		} else if (c=='&') {
123			*t = '\0';
124			(*fn)(txt, value);
125			txt = t+1;
126			value = NULL;
127		}
128		t++;
129	}
130	if (t!=txt)
131		(*fn)(txt, value);
132	return 0;
133}
134
135/*
136 * url syntax: [repo ['/' cmd [ '/' path]]]
137 *   repo: any valid repo url, may contain '/'
138 *   cmd:  log | commit | diff | tree | view | blob | snapshot
139 *   path: any valid path, may contain '/'
140 *
141 */
142void cgit_parse_url(const char *url)
143{
144	char *cmd, *p;
145
146	cgit_repo = NULL;
147	if (!url || url[0] == '\0')
148		return;
149
150	cgit_repo = cgit_get_repoinfo(url);
151	if (cgit_repo) {
152		cgit_query_repo = cgit_repo->url;
153		return;
154	}
155
156	cmd = strchr(url, '/');
157	while (!cgit_repo && cmd) {
158		cmd[0] = '\0';
159		cgit_repo = cgit_get_repoinfo(url);
160		if (cgit_repo == NULL) {
161			cmd[0] = '/';
162			cmd = strchr(cmd + 1, '/');
163			continue;
164		}
165
166		cgit_query_repo = cgit_repo->url;
167		p = strchr(cmd + 1, '/');
168		if (p) {
169			p[0] = '\0';
170			if (p[1])
171				cgit_query_path = trim_end(p + 1, '/');
172		}
173		cgit_cmd = cgit_get_cmd_index(cmd + 1);
174		cgit_query_page = xstrdup(cmd + 1);
175		return;
176	}
177}
178
179char *substr(const char *head, const char *tail)
180{
181	char *buf;
182
183	buf = xmalloc(tail - head + 1);
184	strncpy(buf, head, tail - head);
185	buf[tail - head] = '\0';
186	return buf;
187}
188
189struct commitinfo *cgit_parse_commit(struct commit *commit)
190{
191	struct commitinfo *ret;
192	char *p = commit->buffer, *t = commit->buffer;
193
194	ret = xmalloc(sizeof(*ret));
195	ret->commit = commit;
196	ret->author = NULL;
197	ret->author_email = NULL;
198	ret->committer = NULL;
199	ret->committer_email = NULL;
200	ret->subject = NULL;
201	ret->msg = NULL;
202	ret->msg_encoding = NULL;
203
204	if (p == NULL)
205		return ret;
206
207	if (strncmp(p, "tree ", 5))
208		die("Bad commit: %s", sha1_to_hex(commit->object.sha1));
209	else
210		p += 46; // "tree " + hex[40] + "\n"
211
212	while (!strncmp(p, "parent ", 7))
213		p += 48; // "parent " + hex[40] + "\n"
214
215	if (!strncmp(p, "author ", 7)) {
216		p += 7;
217		t = strchr(p, '<') - 1;
218		ret->author = substr(p, t);
219		p = t;
220		t = strchr(t, '>') + 1;
221		ret->author_email = substr(p, t);
222		ret->author_date = atol(t+1);
223		p = strchr(t, '\n') + 1;
224	}
225
226	if (!strncmp(p, "committer ", 9)) {
227		p += 9;
228		t = strchr(p, '<') - 1;
229		ret->committer = substr(p, t);
230		p = t;
231		t = strchr(t, '>') + 1;
232		ret->committer_email = substr(p, t);
233		ret->committer_date = atol(t+1);
234		p = strchr(t, '\n') + 1;
235	}
236
237	if (!strncmp(p, "encoding ", 9)) {
238		p += 9;
239		t = strchr(p, '\n') + 1;
240		ret->msg_encoding = substr(p, t);
241		p = t;
242	} else
243		ret->msg_encoding = xstrdup(PAGE_ENCODING);
244
245	while (*p && (*p != '\n'))
246		p = strchr(p, '\n') + 1; // skip unknown header fields
247
248	while (*p == '\n')
249		p = strchr(p, '\n') + 1;
250
251	t = strchr(p, '\n');
252	if (t) {
253		if (*t == '\0')
254			ret->subject = "** empty **";
255		else
256			ret->subject = substr(p, t);
257		p = t + 1;
258
259		while (*p == '\n')
260			p = strchr(p, '\n') + 1;
261		ret->msg = xstrdup(p);
262	} else
263		ret->subject = substr(p, p+strlen(p));
264
265	if(strcmp(ret->msg_encoding, PAGE_ENCODING)) {
266		t = reencode_string(ret->subject, PAGE_ENCODING,
267				    ret->msg_encoding);
268		if(t) {
269			free(ret->subject);
270			ret->subject = t;
271		}
272
273		t = reencode_string(ret->msg, PAGE_ENCODING,
274				    ret->msg_encoding);
275		if(t) {
276			free(ret->msg);
277			ret->msg = t;
278		}
279	}
280
281	return ret;
282}
283
284
285struct taginfo *cgit_parse_tag(struct tag *tag)
286{
287	void *data;
288	enum object_type type;
289	unsigned long size;
290	char *p, *t;
291	struct taginfo *ret;
292
293	data = read_sha1_file(tag->object.sha1, &type, &size);
294	if (!data || type != OBJ_TAG) {
295		free(data);
296		return 0;
297	}
298
299	ret = xmalloc(sizeof(*ret));
300	ret->tagger = NULL;
301	ret->tagger_email = NULL;
302	ret->tagger_date = 0;
303	ret->msg = NULL;
304
305	p = data;
306
307	while (p && *p) {
308		if (*p == '\n')
309			break;
310
311		if (!strncmp(p, "tagger ", 7)) {
312			p += 7;
313			t = strchr(p, '<') - 1;
314			ret->tagger = substr(p, t);
315			p = t;
316			t = strchr(t, '>') + 1;
317			ret->tagger_email = substr(p, t);
318			ret->tagger_date = atol(t+1);
319		}
320		p = strchr(p, '\n') + 1;
321	}
322
323	while (p && *p && (*p != '\n'))
324		p = strchr(p, '\n') + 1; // skip unknown tag fields
325
326	while (p && (*p == '\n'))
327		p = strchr(p, '\n') + 1;
328	if (p && *p)
329		ret->msg = xstrdup(p);
330	free(data);
331	return ret;
332}