neocgit

a more 'modern' version of cgit
Log | Files | Refs | Submodules | README | LICENSE | git clone https://git.ne02ptzero.me/git/neocgit

parsing.c (4734B)


      1 /* parsing.c: parsing of config files
      2  *
      3  * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
      4  *
      5  * Licensed under GNU General Public License v2
      6  *   (see COPYING for full license text)
      7  */
      8 
      9 #include "cgit.h"
     10 
     11 /*
     12  * url syntax: [repo ['/' cmd [ '/' path]]]
     13  *   repo: any valid repo url, may contain '/'
     14  *   cmd:  log | commit | diff | tree | view | blob | snapshot
     15  *   path: any valid path, may contain '/'
     16  *
     17  */
     18 void cgit_parse_url(const char *url)
     19 {
     20 	char *c, *cmd, *p;
     21 	struct cgit_repo *repo;
     22 
     23 	if (!url || url[0] == '\0')
     24 		return;
     25 
     26 	ctx.qry.page = NULL;
     27 	ctx.repo = cgit_get_repoinfo(url);
     28 	if (ctx.repo) {
     29 		ctx.qry.repo = ctx.repo->url;
     30 		return;
     31 	}
     32 
     33 	cmd = NULL;
     34 	c = strchr(url, '/');
     35 	while (c) {
     36 		c[0] = '\0';
     37 		repo = cgit_get_repoinfo(url);
     38 		if (repo) {
     39 			ctx.repo = repo;
     40 			cmd = c;
     41 		}
     42 		c[0] = '/';
     43 		c = strchr(c + 1, '/');
     44 	}
     45 
     46 	if (ctx.repo) {
     47 		ctx.qry.repo = ctx.repo->url;
     48 		p = strchr(cmd + 1, '/');
     49 		if (p) {
     50 			p[0] = '\0';
     51 			if (p[1])
     52 				ctx.qry.path = trim_end(p + 1, '/');
     53 		}
     54 		if (cmd[1])
     55 			ctx.qry.page = xstrdup(cmd + 1);
     56 	}
     57 }
     58 
     59 static char *substr(const char *head, const char *tail)
     60 {
     61 	char *buf;
     62 
     63 	if (tail < head)
     64 		return xstrdup("");
     65 	buf = xmalloc(tail - head + 1);
     66 	strncpy(buf, head, tail - head);
     67 	buf[tail - head] = '\0';
     68 	return buf;
     69 }
     70 
     71 static void parse_user(const char *t, char **name, char **email, unsigned long *date, int *tz)
     72 {
     73 	struct ident_split ident;
     74 	unsigned email_len;
     75 
     76 	if (!split_ident_line(&ident, t, strchrnul(t, '\n') - t)) {
     77 		*name = substr(ident.name_begin, ident.name_end);
     78 
     79 		email_len = ident.mail_end - ident.mail_begin;
     80 		*email = xmalloc(strlen("<") + email_len + strlen(">") + 1);
     81 		sprintf(*email, "<%.*s>", email_len, ident.mail_begin);
     82 
     83 		if (ident.date_begin)
     84 			*date = strtoul(ident.date_begin, NULL, 10);
     85 		if (ident.tz_begin)
     86 			*tz = atoi(ident.tz_begin);
     87 	}
     88 }
     89 
     90 #ifdef NO_ICONV
     91 #define reencode(a, b, c)
     92 #else
     93 static const char *reencode(char **txt, const char *src_enc, const char *dst_enc)
     94 {
     95 	char *tmp;
     96 
     97 	if (!txt)
     98 		return NULL;
     99 
    100 	if (!*txt || !src_enc || !dst_enc)
    101 		return *txt;
    102 
    103 	/* no encoding needed if src_enc equals dst_enc */
    104 	if (!strcasecmp(src_enc, dst_enc))
    105 		return *txt;
    106 
    107 	tmp = reencode_string(*txt, dst_enc, src_enc);
    108 	if (tmp) {
    109 		free(*txt);
    110 		*txt = tmp;
    111 	}
    112 	return *txt;
    113 }
    114 #endif
    115 
    116 static const char *next_header_line(const char *p)
    117 {
    118 	p = strchr(p, '\n');
    119 	if (!p)
    120 		return NULL;
    121 	return p + 1;
    122 }
    123 
    124 static int end_of_header(const char *p)
    125 {
    126 	return !p || (*p == '\n');
    127 }
    128 
    129 struct commitinfo *cgit_parse_commit(struct commit *commit)
    130 {
    131 	const int sha1hex_len = 40;
    132 	struct commitinfo *ret;
    133 	const char *p = get_commit_buffer(commit, NULL);
    134 	const char *t;
    135 
    136 	ret = xcalloc(1, sizeof(struct commitinfo));
    137 	ret->commit = commit;
    138 
    139 	if (!p)
    140 		return ret;
    141 
    142 	if (!skip_prefix(p, "tree ", &p))
    143 		die("Bad commit: %s", oid_to_hex(&commit->object.oid));
    144 	p += sha1hex_len + 1;
    145 
    146 	while (skip_prefix(p, "parent ", &p))
    147 		p += sha1hex_len + 1;
    148 
    149 	if (p && skip_prefix(p, "author ", &p)) {
    150 		parse_user(p, &ret->author, &ret->author_email,
    151 			&ret->author_date, &ret->author_tz);
    152 		p = next_header_line(p);
    153 	}
    154 
    155 	if (p && skip_prefix(p, "committer ", &p)) {
    156 		parse_user(p, &ret->committer, &ret->committer_email,
    157 			&ret->committer_date, &ret->committer_tz);
    158 		p = next_header_line(p);
    159 	}
    160 
    161 	if (p && skip_prefix(p, "encoding ", &p)) {
    162 		t = strchr(p, '\n');
    163 		if (t) {
    164 			ret->msg_encoding = substr(p, t + 1);
    165 			p = t + 1;
    166 		}
    167 	}
    168 
    169 	if (!ret->msg_encoding)
    170 		ret->msg_encoding = xstrdup("UTF-8");
    171 
    172 	while (!end_of_header(p))
    173 		p = next_header_line(p);
    174 	while (p && *p == '\n')
    175 		p++;
    176 	if (!p)
    177 		return ret;
    178 
    179 	t = strchrnul(p, '\n');
    180 	ret->subject = substr(p, t);
    181 	while (*t == '\n')
    182 		t++;
    183 	ret->msg = xstrdup(t);
    184 
    185 	reencode(&ret->author, ret->msg_encoding, PAGE_ENCODING);
    186 	reencode(&ret->author_email, ret->msg_encoding, PAGE_ENCODING);
    187 	reencode(&ret->committer, ret->msg_encoding, PAGE_ENCODING);
    188 	reencode(&ret->committer_email, ret->msg_encoding, PAGE_ENCODING);
    189 	reencode(&ret->subject, ret->msg_encoding, PAGE_ENCODING);
    190 	reencode(&ret->msg, ret->msg_encoding, PAGE_ENCODING);
    191 
    192 	return ret;
    193 }
    194 
    195 struct taginfo *cgit_parse_tag(struct tag *tag)
    196 {
    197 	void *data;
    198 	enum object_type type;
    199 	unsigned long size;
    200 	const char *p;
    201 	struct taginfo *ret = NULL;
    202 
    203 	data = read_object_file(&tag->object.oid, &type, &size);
    204 	if (!data || type != OBJ_TAG)
    205 		goto cleanup;
    206 
    207 	ret = xcalloc(1, sizeof(struct taginfo));
    208 
    209 	for (p = data; !end_of_header(p); p = next_header_line(p)) {
    210 		if (skip_prefix(p, "tagger ", &p)) {
    211 			parse_user(p, &ret->tagger, &ret->tagger_email,
    212 				&ret->tagger_date, &ret->tagger_tz);
    213 		}
    214 	}
    215 
    216 	while (p && *p == '\n')
    217 		p++;
    218 
    219 	if (p && *p)
    220 		ret->msg = xstrdup(p);
    221 
    222 cleanup:
    223 	free(data);
    224 	return ret;
    225 }