all repos — cgit @ 5e75128a8bee885d83563d8c521172328d511d12

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
135char *substr(const char *head, const char *tail)
136{
137	char *buf;
138
139	buf = xmalloc(tail - head + 1);
140	strncpy(buf, head, tail - head);
141	buf[tail - head] = '\0';
142	return buf;
143}
144
145struct commitinfo *cgit_parse_commit(struct commit *commit)
146{
147	struct commitinfo *ret;
148	char *p = commit->buffer, *t = commit->buffer;
149
150	ret = xmalloc(sizeof(*ret));
151	ret->commit = commit;
152	ret->author = NULL;
153	ret->author_email = NULL;
154	ret->committer = NULL;
155	ret->committer_email = NULL;
156	ret->subject = NULL;
157	ret->msg = NULL;
158
159	if (strncmp(p, "tree ", 5))
160		die("Bad commit: %s", sha1_to_hex(commit->object.sha1));
161	else
162		p += 46; // "tree " + hex[40] + "\n"
163
164	while (!strncmp(p, "parent ", 7))
165		p += 48; // "parent " + hex[40] + "\n"
166
167	if (!strncmp(p, "author ", 7)) {
168		p += 7;
169		t = strchr(p, '<') - 1;
170		ret->author = substr(p, t);
171		p = t;
172		t = strchr(t, '>') + 1;
173		ret->author_email = substr(p, t);
174		ret->author_date = atol(++t);
175		p = strchr(t, '\n') + 1;
176	}
177
178	if (!strncmp(p, "committer ", 9)) {
179		p += 9;
180		t = strchr(p, '<') - 1;
181		ret->committer = substr(p, t);
182		p = t;
183		t = strchr(t, '>') + 1;
184		ret->committer_email = substr(p, t);
185		ret->committer_date = atol(++t);
186		p = strchr(t, '\n') + 1;
187	}
188
189	while (*p == '\n')
190		p = strchr(p, '\n') + 1;
191
192	t = strchr(p, '\n');
193	if (t && *t) {
194		ret->subject = substr(p, t);
195		p = t + 1;
196
197		while (*p == '\n')
198			p = strchr(p, '\n') + 1;
199		ret->msg = p;
200	}
201	return ret;
202}
203
204
205struct taginfo *cgit_parse_tag(struct tag *tag)
206{
207	void *data;
208	enum object_type type;
209	unsigned long size;
210	char *p, *t;
211	struct taginfo *ret;
212
213	data = read_sha1_file(tag->object.sha1, &type, &size);
214	if (!data || type != OBJ_TAG) {
215		free(data);
216		return 0;
217	}
218
219	ret = xmalloc(sizeof(*ret));
220	ret->tagger = NULL;
221	ret->tagger_email = NULL;
222	ret->tagger_date = 0;
223	ret->msg = NULL;
224
225	p = data;
226
227	while (p && *p) {
228		if (*p == '\n')
229			break;
230
231		if (!strncmp(p, "tagger ", 7)) {
232			p += 7;
233			t = strchr(p, '<') - 1;
234			ret->tagger = substr(p, t);
235			p = t;
236			t = strchr(t, '>') + 1;
237			ret->tagger_email = substr(p, t);
238			ret->tagger_date = atol(++t);
239		}
240		p = strchr(p, '\n') + 1;
241	}
242
243	while (p && (*p == '\n'))
244		p = strchr(p, '\n') + 1;
245	if (p && *p)
246		ret->msg = xstrdup(p);
247	free(data);
248	return ret;
249}