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, "&quot;");
241 p += 6;
242 } else if (c == '&') {
243 strcpy(p, "&amp;");
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, "&quot;");
288 else if (c == '&')
289 lw_write_unsafe(ctx, "&amp;");
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, "&lt;");
495 s2 += 4;
496 break;
497 case '&':
498 strcpy(s2, "&amp;");
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, "&lt;");
526 break;
527 case '&':
528 lw_write_unsafe(ctx, "&amp;");
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 }