annotate src/c/lacweb.c @ 167:2be573fec9a6

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