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