all repos — cgit @ 2919b91d20c80f92bf63bf19daace44ff2d2e9c9

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
203	if (p == NULL)
204		return ret;
205
206	if (strncmp(p, "tree ", 5))
207		die("Bad commit: %s", sha1_to_hex(commit->object.sha1));
208	else
209		p += 46; // "tree " + hex[40] + "\n"
210
211	while (!strncmp(p, "parent ", 7))
212		p += 48; // "parent " + hex[40] + "\n"
213
214	if (!strncmp(p, "author ", 7)) {
215		p += 7;
216		t = strchr(p, '<') - 1;
217		ret->author = substr(p, t);
218		p = t;
219		t = strchr(t, '>') + 1;
220		ret->author_email = substr(p, t);
221		ret->author_date = atol(++t);
222		p = strchr(t, '\n') + 1;
223	}
224
225	if (!strncmp(p, "committer ", 9)) {
226		p += 9;
227		t = strchr(p, '<') - 1;
228		ret->committer = substr(p, t);
229		p = t;
230		t = strchr(t, '>') + 1;
231		ret->committer_email = substr(p, t);
232		ret->committer_date = atol(++t);
233		p = strchr(t, '\n') + 1;
234	}
235
236	while (*p && (*p != '\n'))
237		p = strchr(p, '\n') + 1; // skip unknown header fields
238
239	while (*p == '\n')
240		p = strchr(p, '\n') + 1;
241
242	t = strchr(p, '\n');
243	if (t) {
244		if (*t == '\0')
245			ret->subject = "** empty **";
246		else
247			ret->subject = substr(p, t);
248		p = t + 1;
249
250		while (*p == '\n')
251			p = strchr(p, '\n') + 1;
252		ret->msg = xstrdup(p);
253	} else
254		ret->subject = substr(p, p+strlen(p));
255
256	return ret;
257}
258
259
260struct taginfo *cgit_parse_tag(struct tag *tag)
261{
262	void *data;
263	enum object_type type;
264	unsigned long size;
265	char *p, *t;
266	struct taginfo *ret;
267
268	data = read_sha1_file(tag->object.sha1, &type, &size);
269	if (!data || type != OBJ_TAG) {
270		free(data);
271		return 0;
272	}
273
274	ret = xmalloc(sizeof(*ret));
275	ret->tagger = NULL;
276	ret->tagger_email = NULL;
277	ret->tagger_date = 0;
278	ret->msg = NULL;
279
280	p = data;
281
282	while (p && *p) {
283		if (*p == '\n')
284			break;
285
286		if (!strncmp(p, "tagger ", 7)) {
287			p += 7;
288			t = strchr(p, '<') - 1;
289			ret->tagger = substr(p, t);
290			p = t;
291			t = strchr(t, '>') + 1;
292			ret->tagger_email = substr(p, t);
293			ret->tagger_date = atol(++t);
294		}
295		p = strchr(p, '\n') + 1;
296	}
297
298	while (p && *p && (*p != '\n'))
299		p = strchr(p, '\n') + 1; // skip unknown tag fields
300
301	while (p && (*p == '\n'))
302		p = strchr(p, '\n') + 1;
303	if (p && *p)
304		ret->msg = xstrdup(p);
305	free(data);
306	return ret;
307}