all repos — cgit @ 5ec6e02bd1cc0c05b7cfd0d53371e7d176daec39

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 the reading of yet another configfile after 16 invocations */
 74	if (nesting++ > 16)
 75		return -1;
 76	if (!(f = fopen(filename, "r")))
 77		return -1;
 78	while((len = read_config_line(f, line, &value, sizeof(line))) > 0)
 79		(*fn)(line, value);
 80	fclose(f);
 81	return 0;
 82}
 83
 84char *convert_query_hexchar(char *txt)
 85{
 86	int d1, d2;
 87	if (strlen(txt) < 3) {
 88		*txt = '\0';
 89		return txt-1;
 90	}
 91	d1 = hextoint(*(txt+1));
 92	d2 = hextoint(*(txt+2));
 93	if (d1<0 || d2<0) {
 94		strcpy(txt, txt+3);
 95		return txt-1;
 96	} else {
 97		*txt = d1 * 16 + d2;
 98		strcpy(txt+1, txt+3);
 99		return txt;
100	}
101}
102
103int cgit_parse_query(char *txt, configfn fn)
104{
105	char *t, *value = NULL, c;
106
107	if (!txt)
108		return 0;
109
110	t = txt = xstrdup(txt);
111 
112	while((c=*t) != '\0') {
113		if (c=='=') {
114			*t = '\0';
115			value = t+1;
116		} else if (c=='+') {
117			*t = ' ';
118		} else if (c=='%') {
119			t = convert_query_hexchar(t);
120		} else if (c=='&') {
121			*t = '\0';
122			(*fn)(txt, value);
123			txt = t+1;
124			value = NULL;
125		}
126		t++;
127	}
128	if (t!=txt)
129		(*fn)(txt, value);
130	return 0;
131}
132
133char *substr(const char *head, const char *tail)
134{
135	char *buf;
136
137	buf = xmalloc(tail - head + 1);
138	strncpy(buf, head, tail - head);
139	buf[tail - head] = '\0';
140	return buf;
141}
142
143struct commitinfo *cgit_parse_commit(struct commit *commit)
144{
145	struct commitinfo *ret;
146	char *p = commit->buffer, *t = commit->buffer;
147
148	ret = xmalloc(sizeof(*ret));
149	ret->commit = commit;
150	ret->author = NULL;
151	ret->author_email = NULL;
152	ret->committer = NULL;
153	ret->committer_email = NULL;
154	ret->subject = NULL;
155	ret->msg = NULL;
156
157	if (strncmp(p, "tree ", 5))
158		die("Bad commit: %s", sha1_to_hex(commit->object.sha1));
159	else
160		p += 46; // "tree " + hex[40] + "\n"
161
162	while (!strncmp(p, "parent ", 7))
163		p += 48; // "parent " + hex[40] + "\n"
164
165	if (!strncmp(p, "author ", 7)) {
166		p += 7;
167		t = strchr(p, '<') - 1;
168		ret->author = substr(p, t);
169		p = t;
170		t = strchr(t, '>') + 1;
171		ret->author_email = substr(p, t);
172		ret->author_date = atol(++t);
173		p = strchr(t, '\n') + 1;
174	}
175
176	if (!strncmp(p, "committer ", 9)) {
177		p += 9;
178		t = strchr(p, '<') - 1;
179		ret->committer = substr(p, t);
180		p = t;
181		t = strchr(t, '>') + 1;
182		ret->committer_email = substr(p, t);
183		ret->committer_date = atol(++t);
184		p = strchr(t, '\n') + 1;
185	}
186
187	while (*p == '\n')
188		p = strchr(p, '\n') + 1;
189
190	t = strchr(p, '\n');
191	if (t && *t) {
192		ret->subject = substr(p, t);
193		p = t + 1;
194
195		while (*p == '\n')
196			p = strchr(p, '\n') + 1;
197		ret->msg = p;
198	}
199	return ret;
200}
201
202
203struct taginfo *cgit_parse_tag(struct tag *tag)
204{
205	void *data;
206	enum object_type type;
207	unsigned long size;
208	char *p, *t;
209	struct taginfo *ret;
210
211	data = read_sha1_file(tag->object.sha1, &type, &size);
212	if (!data || type != OBJ_TAG) {
213		free(data);
214		return 0;
215	}
216	
217	ret = xmalloc(sizeof(*ret));
218	ret->tagger = NULL;
219	ret->tagger_email = NULL;
220	ret->tagger_date = 0;
221	ret->msg = NULL;
222
223	p = data;
224
225	while (p && *p) {
226		if (*p == '\n')
227			break;
228
229		if (!strncmp(p, "tagger ", 7)) {
230			p += 7;
231			t = strchr(p, '<') - 1;
232			ret->tagger = substr(p, t);
233			p = t;
234			t = strchr(t, '>') + 1;
235			ret->tagger_email = substr(p, t);
236			ret->tagger_date = atol(++t);
237		}
238		p = strchr(p, '\n') + 1;
239	}
240
241	while (p && (*p == '\n'))
242		p = strchr(p, '\n') + 1;
243	if (p && *p)
244		ret->msg = xstrdup(p);
245	free(data);
246	return ret;
247}