Mercurial > urweb
comparison src/c/urweb.c @ 245:1e24a3e6d614
Rename lacweb.c
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Sun, 31 Aug 2008 08:35:00 -0400 |
parents | src/c/lacweb.c@5dbba661deab |
children | 4d80d6122df1 |
comparison
equal
deleted
inserted
replaced
244:71bafe66dbe1 | 245:1e24a3e6d614 |
---|---|
1 #include <stdlib.h> | |
2 #include <stdio.h> | |
3 #include <string.h> | |
4 #include <ctype.h> | |
5 #include <setjmp.h> | |
6 #include <stdarg.h> | |
7 | |
8 #include "types.h" | |
9 | |
10 lw_unit lw_unit_v = {}; | |
11 | |
12 #define ERROR_BUF_LEN 1024 | |
13 | |
14 struct lw_context { | |
15 char *page, *page_front, *page_back; | |
16 char *heap, *heap_front, *heap_back; | |
17 char **inputs; | |
18 | |
19 jmp_buf jmp_buf; | |
20 | |
21 char error_message[ERROR_BUF_LEN]; | |
22 }; | |
23 | |
24 extern int lw_inputs_len; | |
25 | |
26 lw_context lw_init(size_t page_len, size_t heap_len) { | |
27 lw_context ctx = malloc(sizeof(struct lw_context)); | |
28 | |
29 ctx->page_front = ctx->page = malloc(page_len); | |
30 ctx->page_back = ctx->page_front + page_len; | |
31 | |
32 ctx->heap_front = ctx->heap = malloc(heap_len); | |
33 ctx->heap_back = ctx->heap_front + heap_len; | |
34 | |
35 ctx->inputs = calloc(lw_inputs_len, sizeof(char *)); | |
36 | |
37 ctx->error_message[0] = 0; | |
38 | |
39 return ctx; | |
40 } | |
41 | |
42 void lw_free(lw_context ctx) { | |
43 free(ctx->page); | |
44 free(ctx->heap); | |
45 free(ctx->inputs); | |
46 free(ctx); | |
47 } | |
48 | |
49 void lw_reset_keep_request(lw_context ctx) { | |
50 ctx->page_front = ctx->page; | |
51 ctx->heap_front = ctx->heap; | |
52 | |
53 ctx->error_message[0] = 0; | |
54 } | |
55 | |
56 void lw_reset_keep_error_message(lw_context ctx) { | |
57 ctx->page_front = ctx->page; | |
58 ctx->heap_front = ctx->heap; | |
59 } | |
60 | |
61 void lw_reset(lw_context ctx) { | |
62 lw_reset_keep_request(ctx); | |
63 memset(ctx->inputs, 0, lw_inputs_len * sizeof(char *)); | |
64 } | |
65 | |
66 void lw_handle(lw_context, char *); | |
67 | |
68 failure_kind lw_begin(lw_context ctx, char *path) { | |
69 int r = setjmp(ctx->jmp_buf); | |
70 | |
71 if (r == 0) | |
72 lw_handle(ctx, path); | |
73 | |
74 return r; | |
75 } | |
76 | |
77 void lw_error(lw_context ctx, failure_kind fk, const char *fmt, ...) { | |
78 va_list ap; | |
79 va_start(ap, fmt); | |
80 | |
81 vsnprintf(ctx->error_message, ERROR_BUF_LEN, fmt, ap); | |
82 | |
83 longjmp(ctx->jmp_buf, fk); | |
84 } | |
85 | |
86 char *lw_error_message(lw_context ctx) { | |
87 return ctx->error_message; | |
88 } | |
89 | |
90 int lw_input_num(char*); | |
91 | |
92 void lw_set_input(lw_context ctx, char *name, char *value) { | |
93 int n = lw_input_num(name); | |
94 | |
95 if (n < 0) | |
96 lw_error(ctx, FATAL, "Bad input name %s", name); | |
97 | |
98 if (n >= lw_inputs_len) | |
99 lw_error(ctx, FATAL, "For input name %s, index %d is out of range", name, n); | |
100 | |
101 ctx->inputs[n] = value; | |
102 | |
103 printf("[%d] %s = %s\n", n, name, value); | |
104 } | |
105 | |
106 char *lw_get_input(lw_context ctx, int n) { | |
107 if (n < 0) | |
108 lw_error(ctx, FATAL, "Negative input index %d", n); | |
109 if (n >= lw_inputs_len) | |
110 lw_error(ctx, FATAL, "Out-of-bounds input index %d", n); | |
111 printf("[%d] = %s\n", n, ctx->inputs[n]); | |
112 return ctx->inputs[n]; | |
113 } | |
114 | |
115 char *lw_get_optional_input(lw_context ctx, int n) { | |
116 if (n < 0) | |
117 lw_error(ctx, FATAL, "Negative input index %d", n); | |
118 if (n >= lw_inputs_len) | |
119 lw_error(ctx, FATAL, "Out-of-bounds input index %d", n); | |
120 printf("[%d] = %s\n", n, ctx->inputs[n]); | |
121 return (ctx->inputs[n] == NULL ? "" : ctx->inputs[n]); | |
122 } | |
123 | |
124 static void lw_check_heap(lw_context ctx, size_t extra) { | |
125 if (ctx->heap_back - ctx->heap_front < extra) { | |
126 size_t desired = ctx->heap_back - ctx->heap_front + extra, next; | |
127 char *new_heap; | |
128 | |
129 for (next = ctx->heap_back - ctx->heap_front; next < desired; next *= 2); | |
130 | |
131 new_heap = realloc(ctx->heap, next); | |
132 ctx->heap_front = new_heap; | |
133 ctx->heap_back = new_heap + next; | |
134 | |
135 if (new_heap != ctx->heap) { | |
136 ctx->heap = new_heap; | |
137 lw_error(ctx, UNLIMITED_RETRY, "Couldn't allocate new heap chunk contiguously"); | |
138 } | |
139 | |
140 ctx->heap = new_heap; | |
141 } | |
142 } | |
143 | |
144 void *lw_malloc(lw_context ctx, size_t len) { | |
145 void *result; | |
146 | |
147 lw_check_heap(ctx, len); | |
148 | |
149 result = ctx->heap_front; | |
150 ctx->heap_front += len; | |
151 return result; | |
152 } | |
153 | |
154 int lw_really_send(int sock, const void *buf, ssize_t len) { | |
155 while (len > 0) { | |
156 ssize_t n = send(sock, buf, len, 0); | |
157 | |
158 if (n < 0) | |
159 return n; | |
160 | |
161 buf += n; | |
162 len -= n; | |
163 } | |
164 | |
165 return 0; | |
166 } | |
167 | |
168 int lw_send(lw_context ctx, int sock) { | |
169 return lw_really_send(sock, ctx->page, ctx->page_front - ctx->page); | |
170 } | |
171 | |
172 static void lw_check(lw_context ctx, size_t extra) { | |
173 size_t desired = ctx->page_back - ctx->page_front + extra, next; | |
174 char *new_page; | |
175 | |
176 for (next = ctx->page_back - ctx->page_front; next < desired; next *= 2); | |
177 | |
178 new_page = realloc(ctx->page, next); | |
179 ctx->page_front = new_page + (ctx->page_front - ctx->page); | |
180 ctx->page_back = new_page + (ctx->page_back - ctx->page); | |
181 ctx->page = new_page; | |
182 } | |
183 | |
184 static void lw_writec_unsafe(lw_context ctx, char c) { | |
185 *(ctx->page_front)++ = c; | |
186 } | |
187 | |
188 void lw_writec(lw_context ctx, char c) { | |
189 lw_check(ctx, 1); | |
190 lw_writec_unsafe(ctx, c); | |
191 } | |
192 | |
193 static void lw_write_unsafe(lw_context ctx, const char* s) { | |
194 int len = strlen(s); | |
195 memcpy(ctx->page_front, s, len); | |
196 ctx->page_front += len; | |
197 } | |
198 | |
199 void lw_write(lw_context ctx, const char* s) { | |
200 lw_check(ctx, strlen(s) + 1); | |
201 lw_write_unsafe(ctx, s); | |
202 *ctx->page_front = 0; | |
203 } | |
204 | |
205 | |
206 #define INTS_MAX 50 | |
207 #define FLOATS_MAX 100 | |
208 | |
209 char *lw_Basis_attrifyInt(lw_context ctx, lw_Basis_int n) { | |
210 char *result; | |
211 int len; | |
212 lw_check_heap(ctx, INTS_MAX); | |
213 result = ctx->heap_front; | |
214 sprintf(result, "%d%n", n, &len); | |
215 ctx->heap_front += len+1; | |
216 return result; | |
217 } | |
218 | |
219 char *lw_Basis_attrifyFloat(lw_context ctx, lw_Basis_float n) { | |
220 char *result; | |
221 int len; | |
222 lw_check_heap(ctx, FLOATS_MAX); | |
223 result = ctx->heap_front; | |
224 sprintf(result, "%g%n", n, &len); | |
225 ctx->heap_front += len+1; | |
226 return result; | |
227 } | |
228 | |
229 char *lw_Basis_attrifyString(lw_context ctx, lw_Basis_string s) { | |
230 int len = strlen(s); | |
231 char *result, *p; | |
232 lw_check_heap(ctx, len * 6 + 1); | |
233 | |
234 result = p = ctx->heap_front; | |
235 | |
236 for (; *s; s++) { | |
237 char c = *s; | |
238 | |
239 if (c == '"') { | |
240 strcpy(p, """); | |
241 p += 6; | |
242 } else if (c == '&') { | |
243 strcpy(p, "&"); | |
244 p += 5; | |
245 } | |
246 else if (isprint(c)) | |
247 *p++ = c; | |
248 else { | |
249 int len2; | |
250 sprintf(p, "&#%d;%n", c, &len2); | |
251 p += len2; | |
252 } | |
253 } | |
254 | |
255 *p++ = 0; | |
256 ctx->heap_front = p; | |
257 return result; | |
258 } | |
259 | |
260 static void lw_Basis_attrifyInt_w_unsafe(lw_context ctx, lw_Basis_int n) { | |
261 int len; | |
262 | |
263 sprintf(ctx->page_front, "%d%n", n, &len); | |
264 ctx->page_front += len; | |
265 } | |
266 | |
267 void lw_Basis_attrifyInt_w(lw_context ctx, lw_Basis_int n) { | |
268 lw_check(ctx, INTS_MAX); | |
269 lw_Basis_attrifyInt_w_unsafe(ctx, n); | |
270 } | |
271 | |
272 void lw_Basis_attrifyFloat_w(lw_context ctx, lw_Basis_float n) { | |
273 int len; | |
274 | |
275 lw_check(ctx, FLOATS_MAX); | |
276 sprintf(ctx->page_front, "%g%n", n, &len); | |
277 ctx->page_front += len; | |
278 } | |
279 | |
280 void lw_Basis_attrifyString_w(lw_context ctx, lw_Basis_string s) { | |
281 lw_check(ctx, strlen(s) * 6); | |
282 | |
283 for (; *s; s++) { | |
284 char c = *s; | |
285 | |
286 if (c == '"') | |
287 lw_write_unsafe(ctx, """); | |
288 else if (c == '&') | |
289 lw_write_unsafe(ctx, "&"); | |
290 else if (isprint(c)) | |
291 lw_writec_unsafe(ctx, c); | |
292 else { | |
293 lw_write_unsafe(ctx, "&#"); | |
294 lw_Basis_attrifyInt_w_unsafe(ctx, c); | |
295 lw_writec_unsafe(ctx, ';'); | |
296 } | |
297 } | |
298 } | |
299 | |
300 | |
301 char *lw_Basis_urlifyInt(lw_context ctx, lw_Basis_int n) { | |
302 int len; | |
303 char *r; | |
304 | |
305 lw_check_heap(ctx, INTS_MAX); | |
306 r = ctx->heap_front; | |
307 sprintf(r, "%d%n", n, &len); | |
308 ctx->heap_front += len+1; | |
309 return r; | |
310 } | |
311 | |
312 char *lw_Basis_urlifyFloat(lw_context ctx, lw_Basis_float n) { | |
313 int len; | |
314 char *r; | |
315 | |
316 lw_check_heap(ctx, FLOATS_MAX); | |
317 r = ctx->heap_front; | |
318 sprintf(r, "%g%n", n, &len); | |
319 ctx->heap_front += len+1; | |
320 return r; | |
321 } | |
322 | |
323 char *lw_Basis_urlifyString(lw_context ctx, lw_Basis_string s) { | |
324 char *r, *p; | |
325 | |
326 lw_check_heap(ctx, strlen(s) * 3 + 1); | |
327 | |
328 for (r = p = ctx->heap_front; *s; s++) { | |
329 char c = *s; | |
330 | |
331 if (c == ' ') | |
332 *p++ = '+'; | |
333 else if (isalnum(c)) | |
334 *p++ = c; | |
335 else { | |
336 sprintf(p, "%%%02X", c); | |
337 p += 3; | |
338 } | |
339 } | |
340 | |
341 *p++ = 0; | |
342 ctx->heap_front = p; | |
343 return r; | |
344 } | |
345 | |
346 char *lw_Basis_urlifyBool(lw_context ctx, lw_Basis_bool b) { | |
347 if (b == lw_Basis_False) | |
348 return "0"; | |
349 else | |
350 return "1"; | |
351 } | |
352 | |
353 static void lw_Basis_urlifyInt_w_unsafe(lw_context ctx, lw_Basis_int n) { | |
354 int len; | |
355 | |
356 sprintf(ctx->page_front, "%d%n", n, &len); | |
357 ctx->page_front += len; | |
358 } | |
359 | |
360 void lw_Basis_urlifyInt_w(lw_context ctx, lw_Basis_int n) { | |
361 lw_check(ctx, INTS_MAX); | |
362 lw_Basis_urlifyInt_w_unsafe(ctx, n); | |
363 } | |
364 | |
365 void lw_Basis_urlifyFloat_w(lw_context ctx, lw_Basis_float n) { | |
366 int len; | |
367 | |
368 lw_check(ctx, FLOATS_MAX); | |
369 sprintf(ctx->page_front, "%g%n", n, &len); | |
370 ctx->page_front += len; | |
371 } | |
372 | |
373 void lw_Basis_urlifyString_w(lw_context ctx, lw_Basis_string s) { | |
374 lw_check(ctx, strlen(s) * 3); | |
375 | |
376 for (; *s; s++) { | |
377 char c = *s; | |
378 | |
379 if (c == ' ') | |
380 lw_writec_unsafe(ctx, '+'); | |
381 else if (isalnum(c)) | |
382 lw_writec_unsafe(ctx, c); | |
383 else { | |
384 sprintf(ctx->page_front, "%%%02X", c); | |
385 ctx->page_front += 3; | |
386 } | |
387 } | |
388 } | |
389 | |
390 void lw_Basis_urlifyBool_w(lw_context ctx, lw_Basis_bool b) { | |
391 if (b == lw_Basis_False) | |
392 lw_writec(ctx, '0'); | |
393 else | |
394 lw_writec(ctx, '1'); | |
395 } | |
396 | |
397 | |
398 static char *lw_unurlify_advance(char *s) { | |
399 char *new_s = strchr(s, '/'); | |
400 | |
401 if (new_s) | |
402 *new_s++ = 0; | |
403 else | |
404 new_s = strchr(s, 0); | |
405 | |
406 return new_s; | |
407 } | |
408 | |
409 lw_Basis_int lw_Basis_unurlifyInt(lw_context ctx, char **s) { | |
410 char *new_s = lw_unurlify_advance(*s); | |
411 int r; | |
412 | |
413 r = atoi(*s); | |
414 *s = new_s; | |
415 return r; | |
416 } | |
417 | |
418 lw_Basis_float lw_Basis_unurlifyFloat(lw_context ctx, char **s) { | |
419 char *new_s = lw_unurlify_advance(*s); | |
420 int r; | |
421 | |
422 r = atof(*s); | |
423 *s = new_s; | |
424 return r; | |
425 } | |
426 | |
427 static lw_Basis_string lw_unurlifyString_to(lw_context ctx, char *r, char *s) { | |
428 char *s1, *s2; | |
429 int n; | |
430 | |
431 for (s1 = r, s2 = s; *s2; ++s1, ++s2) { | |
432 char c = *s2; | |
433 | |
434 switch (c) { | |
435 case '+': | |
436 *s1 = ' '; | |
437 break; | |
438 case '%': | |
439 if (s2[1] == 0) | |
440 lw_error(ctx, FATAL, "Missing first character of escaped URL byte"); | |
441 if (s2[2] == 0) | |
442 lw_error(ctx, FATAL, "Missing second character of escaped URL byte"); | |
443 if (sscanf(s2+1, "%02X", &n) != 1) | |
444 lw_error(ctx, FATAL, "Invalid escaped URL byte starting at: %s", s2); | |
445 *s1 = n; | |
446 s2 += 2; | |
447 break; | |
448 default: | |
449 *s1 = c; | |
450 } | |
451 } | |
452 *s1++ = 0; | |
453 return s1; | |
454 } | |
455 | |
456 lw_Basis_bool lw_Basis_unurlifyBool(lw_context ctx, char **s) { | |
457 char *new_s = lw_unurlify_advance(*s); | |
458 lw_Basis_bool r; | |
459 | |
460 if (*s[0] == 0 || !strcmp(*s, "0") || !strcmp(*s, "off")) | |
461 r = lw_Basis_False; | |
462 else | |
463 r = lw_Basis_True; | |
464 | |
465 *s = new_s; | |
466 return r; | |
467 } | |
468 | |
469 lw_Basis_string lw_Basis_unurlifyString(lw_context ctx, char **s) { | |
470 char *new_s = lw_unurlify_advance(*s); | |
471 char *r, *s1, *s2; | |
472 int len, n; | |
473 | |
474 len = strlen(*s); | |
475 lw_check_heap(ctx, len + 1); | |
476 | |
477 r = ctx->heap_front; | |
478 ctx->heap_front = lw_unurlifyString_to(ctx, ctx->heap_front, *s); | |
479 *s = new_s; | |
480 return r; | |
481 } | |
482 | |
483 | |
484 char *lw_Basis_htmlifyString(lw_context ctx, lw_Basis_string s) { | |
485 char *r, *s2; | |
486 | |
487 lw_check_heap(ctx, strlen(s) * 5 + 1); | |
488 | |
489 for (r = s2 = ctx->heap_front; *s; s++) { | |
490 char c = *s; | |
491 | |
492 switch (c) { | |
493 case '<': | |
494 strcpy(s2, "<"); | |
495 s2 += 4; | |
496 break; | |
497 case '&': | |
498 strcpy(s2, "&"); | |
499 s2 += 5; | |
500 break; | |
501 default: | |
502 if (isprint(c)) | |
503 *s2++ = c; | |
504 else { | |
505 int len2; | |
506 sprintf(s2, "&#%d;%n", c, &len2); | |
507 s2 += len2; | |
508 } | |
509 } | |
510 } | |
511 | |
512 *s2++ = 0; | |
513 ctx->heap_front = s2; | |
514 return r; | |
515 } | |
516 | |
517 void lw_Basis_htmlifyString_w(lw_context ctx, lw_Basis_string s) { | |
518 lw_check(ctx, strlen(s) * 5); | |
519 | |
520 for (; *s; s++) { | |
521 char c = *s; | |
522 | |
523 switch (c) { | |
524 case '<': | |
525 lw_write_unsafe(ctx, "<"); | |
526 break; | |
527 case '&': | |
528 lw_write_unsafe(ctx, "&"); | |
529 break; | |
530 default: | |
531 if (isprint(c)) | |
532 lw_writec_unsafe(ctx, c); | |
533 else { | |
534 lw_write_unsafe(ctx, "&#"); | |
535 lw_Basis_attrifyInt_w_unsafe(ctx, c); | |
536 lw_writec_unsafe(ctx, ';'); | |
537 } | |
538 } | |
539 } | |
540 } | |
541 | |
542 lw_Basis_string lw_Basis_strcat(lw_context ctx, lw_Basis_string s1, lw_Basis_string s2) { | |
543 int len = strlen(s1) + strlen(s2) + 1; | |
544 char *s; | |
545 | |
546 lw_check_heap(ctx, len); | |
547 | |
548 s = ctx->heap_front; | |
549 | |
550 strcpy(s, s1); | |
551 strcat(s, s2); | |
552 ctx->heap_front += len; | |
553 | |
554 return s; | |
555 } |