]> gitweb.ps.run Git - ps-cgit/blob - parsing.c
White space around control verbs.
[ps-cgit] / parsing.c
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
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 *cmd, *p;
21
22         ctx.repo = NULL;
23         if (!url || url[0] == '\0')
24                 return;
25
26         ctx.repo = cgit_get_repoinfo(url);
27         if (ctx.repo) {
28                 ctx.qry.repo = ctx.repo->url;
29                 return;
30         }
31
32         cmd = strchr(url, '/');
33         while (!ctx.repo && cmd) {
34                 cmd[0] = '\0';
35                 ctx.repo = cgit_get_repoinfo(url);
36                 if (ctx.repo == NULL) {
37                         cmd[0] = '/';
38                         cmd = strchr(cmd + 1, '/');
39                         continue;
40                 }
41
42                 ctx.qry.repo = ctx.repo->url;
43                 p = strchr(cmd + 1, '/');
44                 if (p) {
45                         p[0] = '\0';
46                         if (p[1])
47                                 ctx.qry.path = trim_end(p + 1, '/');
48                 }
49                 if (cmd[1])
50                         ctx.qry.page = xstrdup(cmd + 1);
51                 return;
52         }
53 }
54
55 char *substr(const char *head, const char *tail)
56 {
57         char *buf;
58
59         if (tail < head)
60                 return xstrdup("");
61         buf = xmalloc(tail - head + 1);
62         strncpy(buf, head, tail - head);
63         buf[tail - head] = '\0';
64         return buf;
65 }
66
67 char *parse_user(char *t, char **name, char **email, unsigned long *date)
68 {
69         char *p = t;
70         int mode = 1;
71
72         while (p && *p) {
73                 if (mode == 1 && *p == '<') {
74                         *name = substr(t, p - 1);
75                         t = p;
76                         mode++;
77                 } else if (mode == 1 && *p == '\n') {
78                         *name = substr(t, p);
79                         p++;
80                         break;
81                 } else if (mode == 2 && *p == '>') {
82                         *email = substr(t, p + 1);
83                         t = p;
84                         mode++;
85                 } else if (mode == 2 && *p == '\n') {
86                         *email = substr(t, p);
87                         p++;
88                         break;
89                 } else if (mode == 3 && isdigit(*p)) {
90                         *date = atol(p);
91                         mode++;
92                 } else if (*p == '\n') {
93                         p++;
94                         break;
95                 }
96                 p++;
97         }
98         return p;
99 }
100
101 #ifdef NO_ICONV
102 #define reencode(a, b, c)
103 #else
104 const char *reencode(char **txt, const char *src_enc, const char *dst_enc)
105 {
106         char *tmp;
107
108         if (!txt)
109                 return NULL;
110
111         if (!*txt || !src_enc || !dst_enc)
112                 return *txt;
113
114         /* no encoding needed if src_enc equals dst_enc */
115         if (!strcasecmp(src_enc, dst_enc))
116                 return *txt;
117
118         tmp = reencode_string(*txt, dst_enc, src_enc);
119         if (tmp) {
120                 free(*txt);
121                 *txt = tmp;
122         }
123         return *txt;
124 }
125 #endif
126
127 struct commitinfo *cgit_parse_commit(struct commit *commit)
128 {
129         struct commitinfo *ret;
130         char *p = commit->buffer, *t;
131
132         ret = xmalloc(sizeof(*ret));
133         ret->commit = commit;
134         ret->author = NULL;
135         ret->author_email = NULL;
136         ret->committer = NULL;
137         ret->committer_email = NULL;
138         ret->subject = NULL;
139         ret->msg = NULL;
140         ret->msg_encoding = NULL;
141
142         if (p == NULL)
143                 return ret;
144
145         if (strncmp(p, "tree ", 5))
146                 die("Bad commit: %s", sha1_to_hex(commit->object.sha1));
147         else
148                 p += 46; // "tree " + hex[40] + "\n"
149
150         while (!strncmp(p, "parent ", 7))
151                 p += 48; // "parent " + hex[40] + "\n"
152
153         if (p && !strncmp(p, "author ", 7)) {
154                 p = parse_user(p + 7, &ret->author, &ret->author_email,
155                         &ret->author_date);
156         }
157
158         if (p && !strncmp(p, "committer ", 9)) {
159                 p = parse_user(p + 9, &ret->committer, &ret->committer_email,
160                         &ret->committer_date);
161         }
162
163         if (p && !strncmp(p, "encoding ", 9)) {
164                 p += 9;
165                 t = strchr(p, '\n');
166                 if (t) {
167                         ret->msg_encoding = substr(p, t + 1);
168                         p = t + 1;
169                 }
170         }
171
172         /* if no special encoding is found, assume UTF-8 */
173         if (!ret->msg_encoding)
174                 ret->msg_encoding = xstrdup("UTF-8");
175
176         // skip unknown header fields
177         while (p && *p && (*p != '\n')) {
178                 p = strchr(p, '\n');
179                 if (p)
180                         p++;
181         }
182
183         // skip empty lines between headers and message
184         while (p && *p == '\n')
185                 p++;
186
187         if (!p)
188                 return ret;
189
190         t = strchr(p, '\n');
191         if (t) {
192                 ret->subject = substr(p, t);
193                 p = t + 1;
194
195                 while (p && *p == '\n') {
196                         p = strchr(p, '\n');
197                         if (p)
198                                 p++;
199                 }
200                 if (p)
201                         ret->msg = xstrdup(p);
202         } else
203                 ret->subject = xstrdup(p);
204
205         reencode(&ret->author, ret->msg_encoding, PAGE_ENCODING);
206         reencode(&ret->author_email, ret->msg_encoding, PAGE_ENCODING);
207         reencode(&ret->committer, ret->msg_encoding, PAGE_ENCODING);
208         reencode(&ret->committer_email, ret->msg_encoding, PAGE_ENCODING);
209         reencode(&ret->subject, ret->msg_encoding, PAGE_ENCODING);
210         reencode(&ret->msg, ret->msg_encoding, PAGE_ENCODING);
211
212         return ret;
213 }
214
215
216 struct taginfo *cgit_parse_tag(struct tag *tag)
217 {
218         void *data;
219         enum object_type type;
220         unsigned long size;
221         char *p;
222         struct taginfo *ret;
223
224         data = read_sha1_file(tag->object.sha1, &type, &size);
225         if (!data || type != OBJ_TAG) {
226                 free(data);
227                 return 0;
228         }
229
230         ret = xmalloc(sizeof(*ret));
231         ret->tagger = NULL;
232         ret->tagger_email = NULL;
233         ret->tagger_date = 0;
234         ret->msg = NULL;
235
236         p = data;
237
238         while (p && *p) {
239                 if (*p == '\n')
240                         break;
241
242                 if (!strncmp(p, "tagger ", 7)) {
243                         p = parse_user(p + 7, &ret->tagger, &ret->tagger_email,
244                                 &ret->tagger_date);
245                 } else {
246                         p = strchr(p, '\n');
247                         if (p)
248                                 p++;
249                 }
250         }
251
252         // skip empty lines between headers and message
253         while (p && *p == '\n')
254                 p++;
255
256         if (p && *p)
257                 ret->msg = xstrdup(p);
258         free(data);
259         return ret;
260 }