summaryrefslogtreecommitdiffabout
authorJonathan Bastien-Filiatrault <joe@x2a.org>2007-10-26 22:13:41 (UTC)
committer Jonathan Bastien-Filiatrault <joe@x2a.org>2007-11-05 23:13:31 (UTC)
commit7858a309d7671109950ec940f893c2d112d36b99 (patch) (unidiff)
tree676723bafc103e232341aa05be4d57ed773b9feb
parentaf0819830445e39584a0137034562086a55deaf2 (diff)
downloadcgit-7858a309d7671109950ec940f893c2d112d36b99.zip
cgit-7858a309d7671109950ec940f893c2d112d36b99.tar.gz
cgit-7858a309d7671109950ec940f893c2d112d36b99.tar.bz2
Convert subject and message with iconv_msg.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--parsing.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/parsing.c b/parsing.c
index f156c12..c731084 100644
--- a/parsing.c
+++ b/parsing.c
@@ -1,374 +1,388 @@
1/* config.c: parsing of config files 1/* config.c: parsing of config files
2 * 2 *
3 * Copyright (C) 2006 Lars Hjemli 3 * Copyright (C) 2006 Lars Hjemli
4 * 4 *
5 * Licensed under GNU General Public License v2 5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text) 6 * (see COPYING for full license text)
7 */ 7 */
8 8
9#include <iconv.h> 9#include <iconv.h>
10 10
11#include "cgit.h" 11#include "cgit.h"
12 12
13int next_char(FILE *f) 13int next_char(FILE *f)
14{ 14{
15 int c = fgetc(f); 15 int c = fgetc(f);
16 if (c=='\r') { 16 if (c=='\r') {
17 c = fgetc(f); 17 c = fgetc(f);
18 if (c!='\n') { 18 if (c!='\n') {
19 ungetc(c, f); 19 ungetc(c, f);
20 c = '\r'; 20 c = '\r';
21 } 21 }
22 } 22 }
23 return c; 23 return c;
24} 24}
25 25
26void skip_line(FILE *f) 26void skip_line(FILE *f)
27{ 27{
28 int c; 28 int c;
29 29
30 while((c=next_char(f)) && c!='\n' && c!=EOF) 30 while((c=next_char(f)) && c!='\n' && c!=EOF)
31 ; 31 ;
32} 32}
33 33
34int read_config_line(FILE *f, char *line, const char **value, int bufsize) 34int read_config_line(FILE *f, char *line, const char **value, int bufsize)
35{ 35{
36 int i = 0, isname = 0; 36 int i = 0, isname = 0;
37 37
38 *value = NULL; 38 *value = NULL;
39 while(i<bufsize-1) { 39 while(i<bufsize-1) {
40 int c = next_char(f); 40 int c = next_char(f);
41 if (!isname && (c=='#' || c==';')) { 41 if (!isname && (c=='#' || c==';')) {
42 skip_line(f); 42 skip_line(f);
43 continue; 43 continue;
44 } 44 }
45 if (!isname && isspace(c)) 45 if (!isname && isspace(c))
46 continue; 46 continue;
47 47
48 if (c=='=' && !*value) { 48 if (c=='=' && !*value) {
49 line[i] = 0; 49 line[i] = 0;
50 *value = &line[i+1]; 50 *value = &line[i+1];
51 } else if (c=='\n' && !isname) { 51 } else if (c=='\n' && !isname) {
52 i = 0; 52 i = 0;
53 continue; 53 continue;
54 } else if (c=='\n' || c==EOF) { 54 } else if (c=='\n' || c==EOF) {
55 line[i] = 0; 55 line[i] = 0;
56 break; 56 break;
57 } else { 57 } else {
58 line[i]=c; 58 line[i]=c;
59 } 59 }
60 isname = 1; 60 isname = 1;
61 i++; 61 i++;
62 } 62 }
63 line[i+1] = 0; 63 line[i+1] = 0;
64 return i; 64 return i;
65} 65}
66 66
67int cgit_read_config(const char *filename, configfn fn) 67int cgit_read_config(const char *filename, configfn fn)
68{ 68{
69 static int nesting; 69 static int nesting;
70 int len; 70 int len;
71 char line[256]; 71 char line[256];
72 const char *value; 72 const char *value;
73 FILE *f; 73 FILE *f;
74 74
75 /* cancel deeply nested include-commands */ 75 /* cancel deeply nested include-commands */
76 if (nesting > 8) 76 if (nesting > 8)
77 return -1; 77 return -1;
78 if (!(f = fopen(filename, "r"))) 78 if (!(f = fopen(filename, "r")))
79 return -1; 79 return -1;
80 nesting++; 80 nesting++;
81 while((len = read_config_line(f, line, &value, sizeof(line))) > 0) 81 while((len = read_config_line(f, line, &value, sizeof(line))) > 0)
82 (*fn)(line, value); 82 (*fn)(line, value);
83 nesting--; 83 nesting--;
84 fclose(f); 84 fclose(f);
85 return 0; 85 return 0;
86} 86}
87 87
88char *convert_query_hexchar(char *txt) 88char *convert_query_hexchar(char *txt)
89{ 89{
90 int d1, d2; 90 int d1, d2;
91 if (strlen(txt) < 3) { 91 if (strlen(txt) < 3) {
92 *txt = '\0'; 92 *txt = '\0';
93 return txt-1; 93 return txt-1;
94 } 94 }
95 d1 = hextoint(*(txt+1)); 95 d1 = hextoint(*(txt+1));
96 d2 = hextoint(*(txt+2)); 96 d2 = hextoint(*(txt+2));
97 if (d1<0 || d2<0) { 97 if (d1<0 || d2<0) {
98 strcpy(txt, txt+3); 98 strcpy(txt, txt+3);
99 return txt-1; 99 return txt-1;
100 } else { 100 } else {
101 *txt = d1 * 16 + d2; 101 *txt = d1 * 16 + d2;
102 strcpy(txt+1, txt+3); 102 strcpy(txt+1, txt+3);
103 return txt; 103 return txt;
104 } 104 }
105} 105}
106 106
107int cgit_parse_query(char *txt, configfn fn) 107int cgit_parse_query(char *txt, configfn fn)
108{ 108{
109 char *t, *value = NULL, c; 109 char *t, *value = NULL, c;
110 110
111 if (!txt) 111 if (!txt)
112 return 0; 112 return 0;
113 113
114 t = txt = xstrdup(txt); 114 t = txt = xstrdup(txt);
115 115
116 while((c=*t) != '\0') { 116 while((c=*t) != '\0') {
117 if (c=='=') { 117 if (c=='=') {
118 *t = '\0'; 118 *t = '\0';
119 value = t+1; 119 value = t+1;
120 } else if (c=='+') { 120 } else if (c=='+') {
121 *t = ' '; 121 *t = ' ';
122 } else if (c=='%') { 122 } else if (c=='%') {
123 t = convert_query_hexchar(t); 123 t = convert_query_hexchar(t);
124 } else if (c=='&') { 124 } else if (c=='&') {
125 *t = '\0'; 125 *t = '\0';
126 (*fn)(txt, value); 126 (*fn)(txt, value);
127 txt = t+1; 127 txt = t+1;
128 value = NULL; 128 value = NULL;
129 } 129 }
130 t++; 130 t++;
131 } 131 }
132 if (t!=txt) 132 if (t!=txt)
133 (*fn)(txt, value); 133 (*fn)(txt, value);
134 return 0; 134 return 0;
135} 135}
136 136
137/* 137/*
138 * url syntax: [repo ['/' cmd [ '/' path]]] 138 * url syntax: [repo ['/' cmd [ '/' path]]]
139 * repo: any valid repo url, may contain '/' 139 * repo: any valid repo url, may contain '/'
140 * cmd: log | commit | diff | tree | view | blob | snapshot 140 * cmd: log | commit | diff | tree | view | blob | snapshot
141 * path: any valid path, may contain '/' 141 * path: any valid path, may contain '/'
142 * 142 *
143 */ 143 */
144void cgit_parse_url(const char *url) 144void cgit_parse_url(const char *url)
145{ 145{
146 char *cmd, *p; 146 char *cmd, *p;
147 147
148 cgit_repo = NULL; 148 cgit_repo = NULL;
149 if (!url || url[0] == '\0') 149 if (!url || url[0] == '\0')
150 return; 150 return;
151 151
152 cgit_repo = cgit_get_repoinfo(url); 152 cgit_repo = cgit_get_repoinfo(url);
153 if (cgit_repo) { 153 if (cgit_repo) {
154 cgit_query_repo = cgit_repo->url; 154 cgit_query_repo = cgit_repo->url;
155 return; 155 return;
156 } 156 }
157 157
158 cmd = strchr(url, '/'); 158 cmd = strchr(url, '/');
159 while (!cgit_repo && cmd) { 159 while (!cgit_repo && cmd) {
160 cmd[0] = '\0'; 160 cmd[0] = '\0';
161 cgit_repo = cgit_get_repoinfo(url); 161 cgit_repo = cgit_get_repoinfo(url);
162 if (cgit_repo == NULL) { 162 if (cgit_repo == NULL) {
163 cmd[0] = '/'; 163 cmd[0] = '/';
164 cmd = strchr(cmd + 1, '/'); 164 cmd = strchr(cmd + 1, '/');
165 continue; 165 continue;
166 } 166 }
167 167
168 cgit_query_repo = cgit_repo->url; 168 cgit_query_repo = cgit_repo->url;
169 p = strchr(cmd + 1, '/'); 169 p = strchr(cmd + 1, '/');
170 if (p) { 170 if (p) {
171 p[0] = '\0'; 171 p[0] = '\0';
172 if (p[1]) 172 if (p[1])
173 cgit_query_path = trim_end(p + 1, '/'); 173 cgit_query_path = trim_end(p + 1, '/');
174 } 174 }
175 cgit_cmd = cgit_get_cmd_index(cmd + 1); 175 cgit_cmd = cgit_get_cmd_index(cmd + 1);
176 cgit_query_page = xstrdup(cmd + 1); 176 cgit_query_page = xstrdup(cmd + 1);
177 return; 177 return;
178 } 178 }
179} 179}
180 180
181static char *iconv_msg(char *msg, const char *encoding) 181static char *iconv_msg(char *msg, const char *encoding)
182{ 182{
183 iconv_t msg_conv = iconv_open(PAGE_ENCODING, encoding); 183 iconv_t msg_conv = iconv_open(PAGE_ENCODING, encoding);
184 size_t inlen = strlen(msg); 184 size_t inlen = strlen(msg);
185 char *in; 185 char *in;
186 char *out; 186 char *out;
187 size_t inleft; 187 size_t inleft;
188 size_t outleft; 188 size_t outleft;
189 char *buf; 189 char *buf;
190 char *ret; 190 char *ret;
191 size_t buf_sz; 191 size_t buf_sz;
192 int again, fail; 192 int again, fail;
193 193
194 if(msg_conv == (iconv_t)-1) 194 if(msg_conv == (iconv_t)-1)
195 return NULL; 195 return NULL;
196 196
197 buf_sz = inlen * 2; 197 buf_sz = inlen * 2;
198 buf = xmalloc(buf_sz+1); 198 buf = xmalloc(buf_sz+1);
199 do { 199 do {
200 in = msg; 200 in = msg;
201 inleft = inlen; 201 inleft = inlen;
202 202
203 out = buf; 203 out = buf;
204 outleft = buf_sz; 204 outleft = buf_sz;
205 iconv(msg_conv, &in, &inleft, &out, &outleft); 205 iconv(msg_conv, &in, &inleft, &out, &outleft);
206 206
207 if(inleft == 0) { 207 if(inleft == 0) {
208 fail = 0; 208 fail = 0;
209 again = 0; 209 again = 0;
210 } else if(inleft != 0 && errno == E2BIG) { 210 } else if(inleft != 0 && errno == E2BIG) {
211 fail = 0; 211 fail = 0;
212 again = 1; 212 again = 1;
213 213
214 buf_sz *= 2; 214 buf_sz *= 2;
215 free(buf); 215 free(buf);
216 buf = xmalloc(buf_sz+1); 216 buf = xmalloc(buf_sz+1);
217 } else { 217 } else {
218 fail = 1; 218 fail = 1;
219 again = 0; 219 again = 0;
220 } 220 }
221 } while(again && !fail); 221 } while(again && !fail);
222 222
223 if(fail) { 223 if(fail) {
224 free(buf); 224 free(buf);
225 ret = NULL; 225 ret = NULL;
226 } else { 226 } else {
227 buf = xrealloc(buf, out - buf); 227 buf = xrealloc(buf, out - buf);
228 *out = 0; 228 *out = 0;
229 ret = buf; 229 ret = buf;
230 } 230 }
231 231
232 iconv_close(msg_conv); 232 iconv_close(msg_conv);
233 233
234 return ret; 234 return ret;
235} 235}
236 236
237char *substr(const char *head, const char *tail) 237char *substr(const char *head, const char *tail)
238{ 238{
239 char *buf; 239 char *buf;
240 240
241 buf = xmalloc(tail - head + 1); 241 buf = xmalloc(tail - head + 1);
242 strncpy(buf, head, tail - head); 242 strncpy(buf, head, tail - head);
243 buf[tail - head] = '\0'; 243 buf[tail - head] = '\0';
244 return buf; 244 return buf;
245} 245}
246 246
247struct commitinfo *cgit_parse_commit(struct commit *commit) 247struct commitinfo *cgit_parse_commit(struct commit *commit)
248{ 248{
249 struct commitinfo *ret; 249 struct commitinfo *ret;
250 char *p = commit->buffer, *t = commit->buffer; 250 char *p = commit->buffer, *t = commit->buffer;
251 251
252 ret = xmalloc(sizeof(*ret)); 252 ret = xmalloc(sizeof(*ret));
253 ret->commit = commit; 253 ret->commit = commit;
254 ret->author = NULL; 254 ret->author = NULL;
255 ret->author_email = NULL; 255 ret->author_email = NULL;
256 ret->committer = NULL; 256 ret->committer = NULL;
257 ret->committer_email = NULL; 257 ret->committer_email = NULL;
258 ret->subject = NULL; 258 ret->subject = NULL;
259 ret->msg = NULL; 259 ret->msg = NULL;
260 ret->msg_encoding = NULL; 260 ret->msg_encoding = NULL;
261 261
262 if (p == NULL) 262 if (p == NULL)
263 return ret; 263 return ret;
264 264
265 if (strncmp(p, "tree ", 5)) 265 if (strncmp(p, "tree ", 5))
266 die("Bad commit: %s", sha1_to_hex(commit->object.sha1)); 266 die("Bad commit: %s", sha1_to_hex(commit->object.sha1));
267 else 267 else
268 p += 46; // "tree " + hex[40] + "\n" 268 p += 46; // "tree " + hex[40] + "\n"
269 269
270 while (!strncmp(p, "parent ", 7)) 270 while (!strncmp(p, "parent ", 7))
271 p += 48; // "parent " + hex[40] + "\n" 271 p += 48; // "parent " + hex[40] + "\n"
272 272
273 if (!strncmp(p, "author ", 7)) { 273 if (!strncmp(p, "author ", 7)) {
274 p += 7; 274 p += 7;
275 t = strchr(p, '<') - 1; 275 t = strchr(p, '<') - 1;
276 ret->author = substr(p, t); 276 ret->author = substr(p, t);
277 p = t; 277 p = t;
278 t = strchr(t, '>') + 1; 278 t = strchr(t, '>') + 1;
279 ret->author_email = substr(p, t); 279 ret->author_email = substr(p, t);
280 ret->author_date = atol(++t); 280 ret->author_date = atol(++t);
281 p = strchr(t, '\n') + 1; 281 p = strchr(t, '\n') + 1;
282 } 282 }
283 283
284 if (!strncmp(p, "committer ", 9)) { 284 if (!strncmp(p, "committer ", 9)) {
285 p += 9; 285 p += 9;
286 t = strchr(p, '<') - 1; 286 t = strchr(p, '<') - 1;
287 ret->committer = substr(p, t); 287 ret->committer = substr(p, t);
288 p = t; 288 p = t;
289 t = strchr(t, '>') + 1; 289 t = strchr(t, '>') + 1;
290 ret->committer_email = substr(p, t); 290 ret->committer_email = substr(p, t);
291 ret->committer_date = atol(++t); 291 ret->committer_date = atol(++t);
292 p = strchr(t, '\n') + 1; 292 p = strchr(t, '\n') + 1;
293 } 293 }
294 294
295 if (!strncmp(p, "encoding ", 9)) { 295 if (!strncmp(p, "encoding ", 9)) {
296 p += 9; 296 p += 9;
297 t = strchr(p, '\n') + 1; 297 t = strchr(p, '\n') + 1;
298 ret->msg_encoding = substr(p, t); 298 ret->msg_encoding = substr(p, t);
299 p = t; 299 p = t;
300 } else 300 } else
301 ret->msg_encoding = xstrdup(PAGE_ENCODING); 301 ret->msg_encoding = xstrdup(PAGE_ENCODING);
302 302
303 while (*p && (*p != '\n')) 303 while (*p && (*p != '\n'))
304 p = strchr(p, '\n') + 1; // skip unknown header fields 304 p = strchr(p, '\n') + 1; // skip unknown header fields
305 305
306 while (*p == '\n') 306 while (*p == '\n')
307 p = strchr(p, '\n') + 1; 307 p = strchr(p, '\n') + 1;
308 308
309 t = strchr(p, '\n'); 309 t = strchr(p, '\n');
310 if (t) { 310 if (t) {
311 if (*t == '\0') 311 if (*t == '\0')
312 ret->subject = "** empty **"; 312 ret->subject = "** empty **";
313 else 313 else
314 ret->subject = substr(p, t); 314 ret->subject = substr(p, t);
315 p = t + 1; 315 p = t + 1;
316 316
317 while (*p == '\n') 317 while (*p == '\n')
318 p = strchr(p, '\n') + 1; 318 p = strchr(p, '\n') + 1;
319 ret->msg = xstrdup(p); 319 ret->msg = xstrdup(p);
320 } else 320 } else
321 ret->subject = substr(p, p+strlen(p)); 321 ret->subject = substr(p, p+strlen(p));
322 322
323 if(strcmp(ret->msg_encoding, PAGE_ENCODING)) {
324 t = iconv_msg(ret->subject, ret->msg_encoding);
325 if(t) {
326 free(ret->subject);
327 ret->subject = t;
328 }
329
330 t = iconv_msg(ret->msg, ret->msg_encoding);
331 if(t) {
332 free(ret->msg);
333 ret->msg = t;
334 }
335 }
336
323 return ret; 337 return ret;
324} 338}
325 339
326 340
327struct taginfo *cgit_parse_tag(struct tag *tag) 341struct taginfo *cgit_parse_tag(struct tag *tag)
328{ 342{
329 void *data; 343 void *data;
330 enum object_type type; 344 enum object_type type;
331 unsigned long size; 345 unsigned long size;
332 char *p, *t; 346 char *p, *t;
333 struct taginfo *ret; 347 struct taginfo *ret;
334 348
335 data = read_sha1_file(tag->object.sha1, &type, &size); 349 data = read_sha1_file(tag->object.sha1, &type, &size);
336 if (!data || type != OBJ_TAG) { 350 if (!data || type != OBJ_TAG) {
337 free(data); 351 free(data);
338 return 0; 352 return 0;
339 } 353 }
340 354
341 ret = xmalloc(sizeof(*ret)); 355 ret = xmalloc(sizeof(*ret));
342 ret->tagger = NULL; 356 ret->tagger = NULL;
343 ret->tagger_email = NULL; 357 ret->tagger_email = NULL;
344 ret->tagger_date = 0; 358 ret->tagger_date = 0;
345 ret->msg = NULL; 359 ret->msg = NULL;
346 360
347 p = data; 361 p = data;
348 362
349 while (p && *p) { 363 while (p && *p) {
350 if (*p == '\n') 364 if (*p == '\n')
351 break; 365 break;
352 366
353 if (!strncmp(p, "tagger ", 7)) { 367 if (!strncmp(p, "tagger ", 7)) {
354 p += 7; 368 p += 7;
355 t = strchr(p, '<') - 1; 369 t = strchr(p, '<') - 1;
356 ret->tagger = substr(p, t); 370 ret->tagger = substr(p, t);
357 p = t; 371 p = t;
358 t = strchr(t, '>') + 1; 372 t = strchr(t, '>') + 1;
359 ret->tagger_email = substr(p, t); 373 ret->tagger_email = substr(p, t);
360 ret->tagger_date = atol(++t); 374 ret->tagger_date = atol(++t);
361 } 375 }
362 p = strchr(p, '\n') + 1; 376 p = strchr(p, '\n') + 1;
363 } 377 }
364 378
365 while (p && *p && (*p != '\n')) 379 while (p && *p && (*p != '\n'))
366 p = strchr(p, '\n') + 1; // skip unknown tag fields 380 p = strchr(p, '\n') + 1; // skip unknown tag fields
367 381
368 while (p && (*p == '\n')) 382 while (p && (*p == '\n'))
369 p = strchr(p, '\n') + 1; 383 p = strchr(p, '\n') + 1;
370 if (p && *p) 384 if (p && *p)
371 ret->msg = xstrdup(p); 385 ret->msg = xstrdup(p);
372 free(data); 386 free(data);
373 return ret; 387 return ret;
374} 388}