annotate src/c/lacweb.c @ 181:31dfab1d4050

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