annotate src/c/urweb.c @ 458:8f65b0fa3b29

Avoid allocating strings for requestHeader
author Adam Chlipala <adamc@hcoop.net>
date Thu, 06 Nov 2008 10:04:03 -0500
parents 360cbc202756
children 21bb5bbba2e9
rev   line source
adamc@436 1 #define _XOPEN_SOURCE
adamc@436 2
adamc@117 3 #include <stdlib.h>
adamc@102 4 #include <stdio.h>
adamc@117 5 #include <string.h>
adamc@457 6 #include <strings.h>
adamc@106 7 #include <ctype.h>
adamc@167 8 #include <setjmp.h>
adamc@167 9 #include <stdarg.h>
adamc@102 10
adamc@102 11 #include "types.h"
adamc@102 12
adamc@311 13 uw_unit uw_unit_v = {};
adamc@102 14
adamc@167 15 #define ERROR_BUF_LEN 1024
adamc@167 16
adamc@323 17 typedef struct regions {
adamc@323 18 struct regions *next;
adamc@323 19 } regions;
adamc@323 20
adamc@425 21 typedef struct {
adamc@425 22 void (*func)(void*);
adamc@425 23 void *arg;
adamc@425 24 } cleanup;
adamc@425 25
adamc@311 26 struct uw_context {
adamc@458 27 char *headers, *headers_end;
adamc@457 28
adamc@117 29 char *page, *page_front, *page_back;
adamc@136 30 char *heap, *heap_front, *heap_back;
adamc@144 31 char **inputs;
adamc@167 32
adamc@272 33 void *db;
adamc@272 34
adamc@167 35 jmp_buf jmp_buf;
adamc@167 36
adamc@323 37 regions *regions;
adamc@323 38
adamc@425 39 cleanup *cleanup, *cleanup_front, *cleanup_back;
adamc@425 40
adamc@167 41 char error_message[ERROR_BUF_LEN];
adamc@117 42 };
adamc@117 43
adamc@311 44 extern int uw_inputs_len;
adamc@144 45
adamc@311 46 uw_context uw_init(size_t page_len, size_t heap_len) {
adamc@311 47 uw_context ctx = malloc(sizeof(struct uw_context));
adamc@136 48
adamc@458 49 ctx->headers = ctx->headers_end = NULL;
adamc@457 50
adamc@117 51 ctx->page_front = ctx->page = malloc(page_len);
adamc@117 52 ctx->page_back = ctx->page_front + page_len;
adamc@136 53
adamc@136 54 ctx->heap_front = ctx->heap = malloc(heap_len);
adamc@136 55 ctx->heap_back = ctx->heap_front + heap_len;
adamc@136 56
adamc@311 57 ctx->inputs = calloc(uw_inputs_len, sizeof(char *));
adamc@144 58
adamc@272 59 ctx->db = NULL;
adamc@272 60
adamc@323 61 ctx->regions = NULL;
adamc@323 62
adamc@425 63 ctx->cleanup_front = ctx->cleanup_back = ctx->cleanup = malloc(0);
adamc@425 64
adamc@167 65 ctx->error_message[0] = 0;
adamc@167 66
adamc@117 67 return ctx;
adamc@106 68 }
adamc@106 69
adamc@311 70 void uw_set_db(uw_context ctx, void *db) {
adamc@272 71 ctx->db = db;
adamc@272 72 }
adamc@272 73
adamc@311 74 void *uw_get_db(uw_context ctx) {
adamc@272 75 return ctx->db;
adamc@272 76 }
adamc@272 77
adamc@311 78 void uw_free(uw_context ctx) {
adamc@117 79 free(ctx->page);
adamc@136 80 free(ctx->heap);
adamc@144 81 free(ctx->inputs);
adamc@425 82 free(ctx->cleanup);
adamc@136 83 free(ctx);
adamc@136 84 }
adamc@136 85
adamc@311 86 void uw_reset_keep_request(uw_context ctx) {
adamc@138 87 ctx->page_front = ctx->page;
adamc@138 88 ctx->heap_front = ctx->heap;
adamc@323 89 ctx->regions = NULL;
adamc@425 90 ctx->cleanup_front = ctx->cleanup;
adamc@167 91
adamc@167 92 ctx->error_message[0] = 0;
adamc@167 93 }
adamc@167 94
adamc@311 95 void uw_reset_keep_error_message(uw_context ctx) {
adamc@167 96 ctx->page_front = ctx->page;
adamc@167 97 ctx->heap_front = ctx->heap;
adamc@323 98 ctx->regions = NULL;
adamc@425 99 ctx->cleanup_front = ctx->cleanup;
adamc@167 100 }
adamc@167 101
adamc@311 102 void uw_reset(uw_context ctx) {
adamc@311 103 uw_reset_keep_request(ctx);
adamc@311 104 memset(ctx->inputs, 0, uw_inputs_len * sizeof(char *));
adamc@144 105 }
adamc@144 106
adamc@311 107 void uw_db_init(uw_context);
adamc@311 108 void uw_handle(uw_context, char *);
adamc@167 109
adamc@311 110 failure_kind uw_begin_init(uw_context ctx) {
adamc@272 111 int r = setjmp(ctx->jmp_buf);
adamc@272 112
adamc@272 113 if (r == 0)
adamc@311 114 uw_db_init(ctx);
adamc@272 115
adamc@272 116 return r;
adamc@272 117 }
adamc@272 118
adamc@458 119 void uw_set_headers(uw_context ctx, char *headers) {
adamc@458 120 char *s = headers, *s2;
adamc@458 121 ctx->headers = headers;
adamc@458 122
adamc@458 123 while (s2 = strchr(s, '\r')) {
adamc@458 124 s = s2;
adamc@458 125
adamc@458 126 if (s[1] == 0)
adamc@458 127 break;
adamc@458 128
adamc@458 129 *s = 0;
adamc@458 130 s += 2;
adamc@458 131 }
adamc@458 132
adamc@458 133 ctx->headers_end = s;
adamc@458 134 }
adamc@458 135
adamc@458 136 failure_kind uw_begin(uw_context ctx, char *path) {
adamc@190 137 int r = setjmp(ctx->jmp_buf);
adamc@190 138
adamc@190 139 if (r == 0)
adamc@311 140 uw_handle(ctx, path);
adamc@167 141
adamc@190 142 return r;
adamc@167 143 }
adamc@167 144
adamc@311 145 __attribute__((noreturn)) void uw_error(uw_context ctx, failure_kind fk, const char *fmt, ...) {
adamc@425 146 cleanup *cl;
adamc@425 147
adamc@167 148 va_list ap;
adamc@167 149 va_start(ap, fmt);
adamc@167 150
adamc@167 151 vsnprintf(ctx->error_message, ERROR_BUF_LEN, fmt, ap);
adamc@167 152
adamc@425 153 for (cl = ctx->cleanup; cl < ctx->cleanup_front; ++cl)
adamc@425 154 cl->func(cl->arg);
adamc@425 155
adamc@425 156 ctx->cleanup_front = ctx->cleanup;
adamc@425 157
adamc@190 158 longjmp(ctx->jmp_buf, fk);
adamc@167 159 }
adamc@167 160
adamc@425 161 void uw_push_cleanup(uw_context ctx, void (*func)(void *), void *arg) {
adamc@425 162 if (ctx->cleanup_front >= ctx->cleanup_back) {
adamc@425 163 int len = ctx->cleanup_back - ctx->cleanup, newLen;
adamc@425 164 if (len == 0)
adamc@425 165 newLen = 1;
adamc@425 166 else
adamc@428 167 newLen = len * 2;
adamc@425 168 ctx->cleanup = realloc(ctx->cleanup, newLen);
adamc@425 169 ctx->cleanup_front = ctx->cleanup + len;
adamc@425 170 ctx->cleanup_back = ctx->cleanup + newLen;
adamc@425 171 }
adamc@425 172
adamc@425 173 ctx->cleanup_front->func = func;
adamc@425 174 ctx->cleanup_front->arg = arg;
adamc@425 175 ++ctx->cleanup_front;
adamc@425 176 }
adamc@425 177
adamc@425 178 void uw_pop_cleanup(uw_context ctx) {
adamc@425 179 if (ctx->cleanup_front == ctx->cleanup)
adamc@425 180 uw_error(ctx, FATAL, "Attempt to pop from empty cleanup action stack");
adamc@425 181
adamc@425 182 --ctx->cleanup_front;
adamc@425 183 ctx->cleanup_front->func(ctx->cleanup_front->arg);
adamc@425 184 }
adamc@425 185
adamc@311 186 char *uw_error_message(uw_context ctx) {
adamc@167 187 return ctx->error_message;
adamc@167 188 }
adamc@167 189
adamc@311 190 int uw_input_num(char*);
adamc@144 191
adamc@311 192 void uw_set_input(uw_context ctx, char *name, char *value) {
adamc@311 193 int n = uw_input_num(name);
adamc@144 194
adamc@169 195 if (n < 0)
adamc@311 196 uw_error(ctx, FATAL, "Bad input name %s", name);
adamc@144 197
adamc@311 198 if (n >= uw_inputs_len)
adamc@311 199 uw_error(ctx, FATAL, "For input name %s, index %d is out of range", name, n);
adamc@169 200
adamc@144 201 ctx->inputs[n] = value;
adamc@144 202
adamc@282 203 //printf("[%d] %s = %s\n", n, name, value);
adamc@144 204 }
adamc@144 205
adamc@311 206 char *uw_get_input(uw_context ctx, int n) {
adamc@169 207 if (n < 0)
adamc@311 208 uw_error(ctx, FATAL, "Negative input index %d", n);
adamc@311 209 if (n >= uw_inputs_len)
adamc@311 210 uw_error(ctx, FATAL, "Out-of-bounds input index %d", n);
adamc@282 211 //printf("[%d] = %s\n", n, ctx->inputs[n]);
adamc@144 212 return ctx->inputs[n];
adamc@138 213 }
adamc@138 214
adamc@311 215 char *uw_get_optional_input(uw_context ctx, int n) {
adamc@190 216 if (n < 0)
adamc@311 217 uw_error(ctx, FATAL, "Negative input index %d", n);
adamc@311 218 if (n >= uw_inputs_len)
adamc@311 219 uw_error(ctx, FATAL, "Out-of-bounds input index %d", n);
adamc@426 220 //printf("[%d] = %s\n", n, ctx->inputs[n]);
adamc@190 221 return (ctx->inputs[n] == NULL ? "" : ctx->inputs[n]);
adamc@190 222 }
adamc@190 223
adamc@311 224 static void uw_check_heap(uw_context ctx, size_t extra) {
adamc@136 225 if (ctx->heap_back - ctx->heap_front < extra) {
adamc@321 226 size_t desired = ctx->heap_front - ctx->heap + extra, next;
adamc@136 227 char *new_heap;
adamc@136 228
adamc@317 229 next = ctx->heap_back - ctx->heap;
adamc@317 230 if (next == 0)
adamc@317 231 next = 1;
adamc@317 232 for (; next < desired; next *= 2);
adamc@136 233
adamc@136 234 new_heap = realloc(ctx->heap, next);
adamc@321 235 ctx->heap_front = new_heap + (ctx->heap_front - ctx->heap);
adamc@169 236 ctx->heap_back = new_heap + next;
adamc@136 237
adamc@136 238 if (new_heap != ctx->heap) {
adamc@136 239 ctx->heap = new_heap;
adamc@311 240 uw_error(ctx, UNLIMITED_RETRY, "Couldn't allocate new heap chunk contiguously");
adamc@136 241 }
adamc@136 242
adamc@169 243 ctx->heap = new_heap;
adamc@136 244 }
adamc@136 245 }
adamc@136 246
adamc@311 247 void *uw_malloc(uw_context ctx, size_t len) {
adamc@136 248 void *result;
adamc@136 249
adamc@311 250 uw_check_heap(ctx, len);
adamc@136 251
adamc@136 252 result = ctx->heap_front;
adamc@136 253 ctx->heap_front += len;
adamc@136 254 return result;
adamc@117 255 }
adamc@117 256
adamc@323 257 void uw_begin_region(uw_context ctx) {
adamc@323 258 regions *r = (regions *) ctx->heap_front;
adamc@323 259
adamc@323 260 uw_check_heap(ctx, sizeof(regions));
adamc@323 261
adamc@323 262 ctx->heap_front += sizeof(regions);
adamc@323 263
adamc@323 264 r->next = ctx->regions;
adamc@323 265 ctx->regions = r;
adamc@323 266 }
adamc@323 267
adamc@323 268 void uw_end_region(uw_context ctx) {
adamc@323 269 regions *r = ctx->regions;
adamc@323 270
adamc@323 271 if (r == NULL)
adamc@323 272 uw_error(ctx, FATAL, "Region stack underflow");
adamc@323 273
adamc@323 274 ctx->heap_front = (char *) r;
adamc@323 275 ctx->regions = r->next;
adamc@323 276 }
adamc@323 277
adamc@324 278 void uw_memstats(uw_context ctx) {
adamc@324 279 printf("Page: %d/%d\n", ctx->page_front - ctx->page, ctx->page_back - ctx->page);
adamc@324 280 printf("Heap: %d/%d\n", ctx->heap_front - ctx->heap, ctx->heap_back - ctx->heap);
adamc@324 281 }
adamc@324 282
adamc@436 283 int uw_really_send(int sock, const void *buf, size_t len) {
adamc@117 284 while (len > 0) {
adamc@436 285 size_t n = send(sock, buf, len, 0);
adamc@117 286
adamc@117 287 if (n < 0)
adamc@117 288 return n;
adamc@117 289
adamc@117 290 buf += n;
adamc@117 291 len -= n;
adamc@117 292 }
adamc@117 293
adamc@117 294 return 0;
adamc@117 295 }
adamc@117 296
adamc@311 297 int uw_send(uw_context ctx, int sock) {
adamc@311 298 return uw_really_send(sock, ctx->page, ctx->page_front - ctx->page);
adamc@117 299 }
adamc@117 300
adamc@311 301 static void uw_check(uw_context ctx, size_t extra) {
adamc@321 302 size_t desired = ctx->page_front - ctx->page + extra, next;
adamc@117 303 char *new_page;
adamc@117 304
adamc@317 305 next = ctx->page_back - ctx->page;
adamc@428 306 if (next < desired) {
adamc@428 307 if (next == 0)
adamc@428 308 next = 1;
adamc@428 309 for (; next < desired; next *= 2);
adamc@117 310
adamc@428 311 new_page = realloc(ctx->page, next);
adamc@428 312 ctx->page_front = new_page + (ctx->page_front - ctx->page);
adamc@428 313 ctx->page_back = new_page + next;
adamc@428 314 ctx->page = new_page;
adamc@428 315 }
adamc@117 316 }
adamc@117 317
adamc@311 318 static void uw_writec_unsafe(uw_context ctx, char c) {
adamc@117 319 *(ctx->page_front)++ = c;
adamc@117 320 }
adamc@117 321
adamc@311 322 void uw_writec(uw_context ctx, char c) {
adamc@311 323 uw_check(ctx, 1);
adamc@311 324 uw_writec_unsafe(ctx, c);
adamc@117 325 }
adamc@117 326
adamc@311 327 static void uw_write_unsafe(uw_context ctx, const char* s) {
adamc@117 328 int len = strlen(s);
adamc@117 329 memcpy(ctx->page_front, s, len);
adamc@117 330 ctx->page_front += len;
adamc@117 331 }
adamc@117 332
adamc@311 333 void uw_write(uw_context ctx, const char* s) {
adamc@311 334 uw_check(ctx, strlen(s) + 1);
adamc@311 335 uw_write_unsafe(ctx, s);
adamc@183 336 *ctx->page_front = 0;
adamc@102 337 }
adamc@106 338
adamc@135 339
adamc@311 340 char *uw_Basis_attrifyInt(uw_context ctx, uw_Basis_int n) {
adamc@136 341 char *result;
adamc@136 342 int len;
adamc@311 343 uw_check_heap(ctx, INTS_MAX);
adamc@136 344 result = ctx->heap_front;
adamc@276 345 sprintf(result, "%lld%n", n, &len);
adamc@137 346 ctx->heap_front += len+1;
adamc@136 347 return result;
adamc@106 348 }
adamc@106 349
adamc@311 350 char *uw_Basis_attrifyFloat(uw_context ctx, uw_Basis_float n) {
adamc@136 351 char *result;
adamc@136 352 int len;
adamc@311 353 uw_check_heap(ctx, FLOATS_MAX);
adamc@136 354 result = ctx->heap_front;
adamc@136 355 sprintf(result, "%g%n", n, &len);
adamc@137 356 ctx->heap_front += len+1;
adamc@136 357 return result;
adamc@106 358 }
adamc@106 359
adamc@311 360 char *uw_Basis_attrifyString(uw_context ctx, uw_Basis_string s) {
adamc@136 361 int len = strlen(s);
adamc@136 362 char *result, *p;
adamc@311 363 uw_check_heap(ctx, len * 6 + 1);
adamc@136 364
adamc@136 365 result = p = ctx->heap_front;
adamc@136 366
adamc@136 367 for (; *s; s++) {
adamc@136 368 char c = *s;
adamc@136 369
adamc@136 370 if (c == '"') {
adamc@136 371 strcpy(p, "&quot;");
adamc@136 372 p += 6;
adamc@136 373 } else if (c == '&') {
adamc@136 374 strcpy(p, "&amp;");
adamc@136 375 p += 5;
adamc@136 376 }
adamc@136 377 else if (isprint(c))
adamc@136 378 *p++ = c;
adamc@136 379 else {
adamc@136 380 int len2;
adamc@136 381 sprintf(p, "&#%d;%n", c, &len2);
adamc@136 382 p += len2;
adamc@136 383 }
adamc@136 384 }
adamc@136 385
adamc@137 386 *p++ = 0;
adamc@136 387 ctx->heap_front = p;
adamc@136 388 return result;
adamc@106 389 }
adamc@106 390
adamc@311 391 static void uw_Basis_attrifyInt_w_unsafe(uw_context ctx, uw_Basis_int n) {
adamc@117 392 int len;
adamc@117 393
adamc@276 394 sprintf(ctx->page_front, "%lld%n", n, &len);
adamc@117 395 ctx->page_front += len;
adamc@106 396 }
adamc@106 397
adamc@428 398 uw_unit uw_Basis_attrifyInt_w(uw_context ctx, uw_Basis_int n) {
adamc@311 399 uw_check(ctx, INTS_MAX);
adamc@311 400 uw_Basis_attrifyInt_w_unsafe(ctx, n);
adamc@428 401
adamc@428 402 return uw_unit_v;
adamc@106 403 }
adamc@106 404
adamc@428 405 uw_unit uw_Basis_attrifyFloat_w(uw_context ctx, uw_Basis_float n) {
adamc@117 406 int len;
adamc@117 407
adamc@311 408 uw_check(ctx, FLOATS_MAX);
adamc@117 409 sprintf(ctx->page_front, "%g%n", n, &len);
adamc@117 410 ctx->page_front += len;
adamc@428 411
adamc@428 412 return uw_unit_v;
adamc@117 413 }
adamc@117 414
adamc@428 415 uw_unit uw_Basis_attrifyString_w(uw_context ctx, uw_Basis_string s) {
adamc@311 416 uw_check(ctx, strlen(s) * 6);
adamc@117 417
adamc@106 418 for (; *s; s++) {
adamc@106 419 char c = *s;
adamc@106 420
adamc@106 421 if (c == '"')
adamc@311 422 uw_write_unsafe(ctx, "&quot;");
adamc@136 423 else if (c == '&')
adamc@311 424 uw_write_unsafe(ctx, "&amp;");
adamc@106 425 else if (isprint(c))
adamc@311 426 uw_writec_unsafe(ctx, c);
adamc@106 427 else {
adamc@311 428 uw_write_unsafe(ctx, "&#");
adamc@311 429 uw_Basis_attrifyInt_w_unsafe(ctx, c);
adamc@311 430 uw_writec_unsafe(ctx, ';');
adamc@106 431 }
adamc@106 432 }
adamc@428 433
adamc@428 434 return uw_unit_v;
adamc@106 435 }
adamc@120 436
adamc@120 437
adamc@311 438 char *uw_Basis_urlifyInt(uw_context ctx, uw_Basis_int n) {
adamc@137 439 int len;
adamc@137 440 char *r;
adamc@137 441
adamc@311 442 uw_check_heap(ctx, INTS_MAX);
adamc@137 443 r = ctx->heap_front;
adamc@276 444 sprintf(r, "%lld%n", n, &len);
adamc@137 445 ctx->heap_front += len+1;
adamc@137 446 return r;
adamc@120 447 }
adamc@120 448
adamc@311 449 char *uw_Basis_urlifyFloat(uw_context ctx, uw_Basis_float n) {
adamc@137 450 int len;
adamc@137 451 char *r;
adamc@137 452
adamc@311 453 uw_check_heap(ctx, FLOATS_MAX);
adamc@137 454 r = ctx->heap_front;
adamc@137 455 sprintf(r, "%g%n", n, &len);
adamc@137 456 ctx->heap_front += len+1;
adamc@137 457 return r;
adamc@120 458 }
adamc@120 459
adamc@311 460 char *uw_Basis_urlifyString(uw_context ctx, uw_Basis_string s) {
adamc@137 461 char *r, *p;
adamc@137 462
adamc@311 463 uw_check_heap(ctx, strlen(s) * 3 + 1);
adamc@137 464
adamc@137 465 for (r = p = ctx->heap_front; *s; s++) {
adamc@137 466 char c = *s;
adamc@137 467
adamc@137 468 if (c == ' ')
adamc@137 469 *p++ = '+';
adamc@137 470 else if (isalnum(c))
adamc@137 471 *p++ = c;
adamc@137 472 else {
adamc@137 473 sprintf(p, "%%%02X", c);
adamc@137 474 p += 3;
adamc@137 475 }
adamc@137 476 }
adamc@137 477
adamc@137 478 *p++ = 0;
adamc@137 479 ctx->heap_front = p;
adamc@137 480 return r;
adamc@120 481 }
adamc@120 482
adamc@311 483 char *uw_Basis_urlifyBool(uw_context ctx, uw_Basis_bool b) {
adamc@311 484 if (b == uw_Basis_False)
adamc@186 485 return "0";
adamc@186 486 else
adamc@186 487 return "1";
adamc@186 488 }
adamc@186 489
adamc@311 490 static void uw_Basis_urlifyInt_w_unsafe(uw_context ctx, uw_Basis_int n) {
adamc@120 491 int len;
adamc@120 492
adamc@276 493 sprintf(ctx->page_front, "%lld%n", n, &len);
adamc@120 494 ctx->page_front += len;
adamc@120 495 }
adamc@120 496
adamc@428 497 uw_unit uw_Basis_urlifyInt_w(uw_context ctx, uw_Basis_int n) {
adamc@311 498 uw_check(ctx, INTS_MAX);
adamc@311 499 uw_Basis_urlifyInt_w_unsafe(ctx, n);
adamc@428 500
adamc@428 501 return uw_unit_v;
adamc@120 502 }
adamc@120 503
adamc@428 504 uw_unit uw_Basis_urlifyFloat_w(uw_context ctx, uw_Basis_float n) {
adamc@120 505 int len;
adamc@120 506
adamc@311 507 uw_check(ctx, FLOATS_MAX);
adamc@120 508 sprintf(ctx->page_front, "%g%n", n, &len);
adamc@120 509 ctx->page_front += len;
adamc@428 510
adamc@428 511 return uw_unit_v;
adamc@120 512 }
adamc@120 513
adamc@428 514 uw_unit uw_Basis_urlifyString_w(uw_context ctx, uw_Basis_string s) {
adamc@311 515 uw_check(ctx, strlen(s) * 3);
adamc@120 516
adamc@120 517 for (; *s; s++) {
adamc@120 518 char c = *s;
adamc@120 519
adamc@120 520 if (c == ' ')
adamc@311 521 uw_writec_unsafe(ctx, '+');
adamc@120 522 else if (isalnum(c))
adamc@311 523 uw_writec_unsafe(ctx, c);
adamc@120 524 else {
adamc@120 525 sprintf(ctx->page_front, "%%%02X", c);
adamc@120 526 ctx->page_front += 3;
adamc@120 527 }
adamc@120 528 }
adamc@428 529
adamc@428 530 return uw_unit_v;
adamc@120 531 }
adamc@120 532
adamc@428 533 uw_unit uw_Basis_urlifyBool_w(uw_context ctx, uw_Basis_bool b) {
adamc@311 534 if (b == uw_Basis_False)
adamc@311 535 uw_writec(ctx, '0');
adamc@186 536 else
adamc@311 537 uw_writec(ctx, '1');
adamc@428 538
adamc@428 539 return uw_unit_v;
adamc@186 540 }
adamc@186 541
adamc@120 542
adamc@311 543 static char *uw_unurlify_advance(char *s) {
adamc@144 544 char *new_s = strchr(s, '/');
adamc@120 545
adamc@120 546 if (new_s)
adamc@120 547 *new_s++ = 0;
adamc@120 548 else
adamc@144 549 new_s = strchr(s, 0);
adamc@144 550
adamc@144 551 return new_s;
adamc@144 552 }
adamc@144 553
adamc@311 554 uw_Basis_int uw_Basis_unurlifyInt(uw_context ctx, char **s) {
adamc@311 555 char *new_s = uw_unurlify_advance(*s);
adamc@311 556 uw_Basis_int r;
adamc@120 557
adamc@276 558 r = atoll(*s);
adamc@120 559 *s = new_s;
adamc@120 560 return r;
adamc@120 561 }
adamc@120 562
adamc@311 563 uw_Basis_float uw_Basis_unurlifyFloat(uw_context ctx, char **s) {
adamc@311 564 char *new_s = uw_unurlify_advance(*s);
adamc@311 565 uw_Basis_float r;
adamc@120 566
adamc@120 567 r = atof(*s);
adamc@120 568 *s = new_s;
adamc@120 569 return r;
adamc@120 570 }
adamc@120 571
adamc@311 572 static uw_Basis_string uw_unurlifyString_to(uw_context ctx, char *r, char *s) {
adamc@144 573 char *s1, *s2;
adamc@144 574 int n;
adamc@136 575
adamc@144 576 for (s1 = r, s2 = s; *s2; ++s1, ++s2) {
adamc@136 577 char c = *s2;
adamc@136 578
adamc@136 579 switch (c) {
adamc@136 580 case '+':
adamc@136 581 *s1 = ' ';
adamc@136 582 break;
adamc@136 583 case '%':
adamc@169 584 if (s2[1] == 0)
adamc@311 585 uw_error(ctx, FATAL, "Missing first character of escaped URL byte");
adamc@169 586 if (s2[2] == 0)
adamc@311 587 uw_error(ctx, FATAL, "Missing second character of escaped URL byte");
adamc@169 588 if (sscanf(s2+1, "%02X", &n) != 1)
adamc@311 589 uw_error(ctx, FATAL, "Invalid escaped URL byte starting at: %s", s2);
adamc@136 590 *s1 = n;
adamc@136 591 s2 += 2;
adamc@136 592 break;
adamc@136 593 default:
adamc@136 594 *s1 = c;
adamc@136 595 }
adamc@136 596 }
adamc@136 597 *s1++ = 0;
adamc@144 598 return s1;
adamc@144 599 }
adamc@144 600
adamc@311 601 uw_Basis_bool uw_Basis_unurlifyBool(uw_context ctx, char **s) {
adamc@311 602 char *new_s = uw_unurlify_advance(*s);
adamc@311 603 uw_Basis_bool r;
adamc@186 604
adamc@186 605 if (*s[0] == 0 || !strcmp(*s, "0") || !strcmp(*s, "off"))
adamc@311 606 r = uw_Basis_False;
adamc@186 607 else
adamc@311 608 r = uw_Basis_True;
adamc@186 609
adamc@186 610 *s = new_s;
adamc@186 611 return r;
adamc@186 612 }
adamc@186 613
adamc@311 614 uw_Basis_string uw_Basis_unurlifyString(uw_context ctx, char **s) {
adamc@311 615 char *new_s = uw_unurlify_advance(*s);
adamc@144 616 char *r, *s1, *s2;
adamc@144 617 int len, n;
adamc@144 618
adamc@200 619 len = strlen(*s);
adamc@311 620 uw_check_heap(ctx, len + 1);
adamc@144 621
adamc@144 622 r = ctx->heap_front;
adamc@311 623 ctx->heap_front = uw_unurlifyString_to(ctx, ctx->heap_front, *s);
adamc@136 624 *s = new_s;
adamc@136 625 return r;
adamc@120 626 }
adamc@135 627
adamc@135 628
adamc@311 629 char *uw_Basis_htmlifyInt(uw_context ctx, uw_Basis_int n) {
adamc@286 630 int len;
adamc@286 631 char *r;
adamc@286 632
adamc@311 633 uw_check_heap(ctx, INTS_MAX);
adamc@286 634 r = ctx->heap_front;
adamc@286 635 sprintf(r, "%lld%n", n, &len);
adamc@286 636 ctx->heap_front += len+1;
adamc@286 637 return r;
adamc@286 638 }
adamc@286 639
adamc@428 640 uw_unit uw_Basis_htmlifyInt_w(uw_context ctx, uw_Basis_int n) {
adamc@286 641 int len;
adamc@286 642
adamc@311 643 uw_check(ctx, INTS_MAX);
adamc@286 644 sprintf(ctx->page_front, "%lld%n", n, &len);
adamc@286 645 ctx->page_front += len;
adamc@428 646
adamc@428 647 return uw_unit_v;
adamc@286 648 }
adamc@286 649
adamc@311 650 char *uw_Basis_htmlifyFloat(uw_context ctx, uw_Basis_float n) {
adamc@286 651 int len;
adamc@286 652 char *r;
adamc@286 653
adamc@311 654 uw_check_heap(ctx, FLOATS_MAX);
adamc@286 655 r = ctx->heap_front;
adamc@286 656 sprintf(r, "%g%n", n, &len);
adamc@286 657 ctx->heap_front += len+1;
adamc@286 658 return r;
adamc@286 659 }
adamc@286 660
adamc@428 661 uw_unit uw_Basis_htmlifyFloat_w(uw_context ctx, uw_Basis_float n) {
adamc@286 662 int len;
adamc@286 663
adamc@311 664 uw_check(ctx, FLOATS_MAX);
adamc@286 665 sprintf(ctx->page_front, "%g%n", n, &len);
adamc@286 666 ctx->page_front += len;
adamc@428 667
adamc@428 668 return uw_unit_v;
adamc@286 669 }
adamc@286 670
adamc@311 671 char *uw_Basis_htmlifyString(uw_context ctx, uw_Basis_string s) {
adamc@137 672 char *r, *s2;
adamc@137 673
adamc@311 674 uw_check_heap(ctx, strlen(s) * 5 + 1);
adamc@137 675
adamc@137 676 for (r = s2 = ctx->heap_front; *s; s++) {
adamc@137 677 char c = *s;
adamc@137 678
adamc@137 679 switch (c) {
adamc@137 680 case '<':
adamc@137 681 strcpy(s2, "&lt;");
adamc@137 682 s2 += 4;
adamc@137 683 break;
adamc@137 684 case '&':
adamc@137 685 strcpy(s2, "&amp;");
adamc@137 686 s2 += 5;
adamc@137 687 break;
adamc@137 688 default:
adamc@137 689 if (isprint(c))
adamc@137 690 *s2++ = c;
adamc@137 691 else {
adamc@137 692 int len2;
adamc@137 693 sprintf(s2, "&#%d;%n", c, &len2);
adamc@137 694 s2 += len2;
adamc@137 695 }
adamc@137 696 }
adamc@137 697 }
adamc@137 698
adamc@137 699 *s2++ = 0;
adamc@137 700 ctx->heap_front = s2;
adamc@137 701 return r;
adamc@135 702 }
adamc@135 703
adamc@428 704 uw_unit uw_Basis_htmlifyString_w(uw_context ctx, uw_Basis_string s) {
adamc@321 705 uw_check(ctx, strlen(s) * 6);
adamc@135 706
adamc@135 707 for (; *s; s++) {
adamc@135 708 char c = *s;
adamc@135 709
adamc@135 710 switch (c) {
adamc@135 711 case '<':
adamc@311 712 uw_write_unsafe(ctx, "&lt;");
adamc@135 713 break;
adamc@135 714 case '&':
adamc@311 715 uw_write_unsafe(ctx, "&amp;");
adamc@135 716 break;
adamc@135 717 default:
adamc@135 718 if (isprint(c))
adamc@311 719 uw_writec_unsafe(ctx, c);
adamc@135 720 else {
adamc@311 721 uw_write_unsafe(ctx, "&#");
adamc@311 722 uw_Basis_attrifyInt_w_unsafe(ctx, c);
adamc@311 723 uw_writec_unsafe(ctx, ';');
adamc@135 724 }
adamc@135 725 }
adamc@135 726 }
adamc@428 727
adamc@428 728 return uw_unit_v;
adamc@135 729 }
adamc@180 730
adamc@311 731 uw_Basis_string uw_Basis_htmlifyBool(uw_context ctx, uw_Basis_bool b) {
adamc@311 732 if (b == uw_Basis_False)
adamc@286 733 return "False";
adamc@286 734 else
adamc@286 735 return "True";
adamc@286 736 }
adamc@286 737
adamc@428 738 uw_unit uw_Basis_htmlifyBool_w(uw_context ctx, uw_Basis_bool b) {
adamc@311 739 if (b == uw_Basis_False) {
adamc@311 740 uw_check(ctx, 6);
adamc@286 741 strcpy(ctx->page_front, "False");
adamc@286 742 ctx->page_front += 5;
adamc@286 743 } else {
adamc@311 744 uw_check(ctx, 5);
adamc@286 745 strcpy(ctx->page_front, "True");
adamc@286 746 ctx->page_front += 4;
adamc@286 747 }
adamc@428 748
adamc@428 749 return uw_unit_v;
adamc@286 750 }
adamc@286 751
adamc@436 752 #define TIME_FMT "%x %X"
adamc@438 753 #define TIME_FMT_PG "%Y-%m-%d %T"
adamc@436 754
adamc@436 755 uw_Basis_string uw_Basis_htmlifyTime(uw_context ctx, uw_Basis_time t) {
adamc@436 756 size_t len;
adamc@436 757 char *r;
adamc@436 758 struct tm stm;
adamc@436 759
adamc@436 760 if (localtime_r(&t, &stm)) {
adamc@436 761 uw_check_heap(ctx, TIMES_MAX);
adamc@436 762 r = ctx->heap_front;
adamc@436 763 len = strftime(r, TIMES_MAX, TIME_FMT, &stm);
adamc@436 764 ctx->heap_front += len+1;
adamc@436 765 return r;
adamc@436 766 } else
adamc@436 767 return "<i>Invalid time</i>";
adamc@436 768 }
adamc@436 769
adamc@436 770 uw_unit uw_Basis_htmlifyTime_w(uw_context ctx, uw_Basis_time t) {
adamc@436 771 size_t len;
adamc@436 772 char *r;
adamc@436 773 struct tm stm;
adamc@436 774
adamc@436 775 if (localtime_r(&t, &stm)) {
adamc@436 776 uw_check(ctx, TIMES_MAX);
adamc@436 777 r = ctx->page_front;
adamc@436 778 len = strftime(r, TIMES_MAX, TIME_FMT, &stm);
adamc@436 779 ctx->page_front += len;
adamc@436 780 } else {
adamc@436 781 uw_check(ctx, 20);
adamc@436 782 strcpy(ctx->page_front, "<i>Invalid time</i>");
adamc@436 783 ctx->page_front += 19;
adamc@436 784 }
adamc@436 785
adamc@436 786 return uw_unit_v;
adamc@436 787 }
adamc@436 788
adamc@311 789 uw_Basis_string uw_Basis_strcat(uw_context ctx, uw_Basis_string s1, uw_Basis_string s2) {
adamc@180 790 int len = strlen(s1) + strlen(s2) + 1;
adamc@180 791 char *s;
adamc@180 792
adamc@311 793 uw_check_heap(ctx, len);
adamc@180 794
adamc@180 795 s = ctx->heap_front;
adamc@180 796
adamc@180 797 strcpy(s, s1);
adamc@180 798 strcat(s, s2);
adamc@180 799 ctx->heap_front += len;
adamc@180 800
adamc@180 801 return s;
adamc@180 802 }
adamc@278 803
adamc@311 804 uw_Basis_string uw_Basis_strdup(uw_context ctx, uw_Basis_string s1) {
adamc@278 805 int len = strlen(s1) + 1;
adamc@278 806 char *s;
adamc@278 807
adamc@311 808 uw_check_heap(ctx, len);
adamc@278 809
adamc@278 810 s = ctx->heap_front;
adamc@278 811
adamc@278 812 strcpy(s, s1);
adamc@278 813 ctx->heap_front += len;
adamc@278 814
adamc@278 815 return s;
adamc@278 816 }
adamc@280 817
adamc@280 818
adamc@311 819 char *uw_Basis_sqlifyInt(uw_context ctx, uw_Basis_int n) {
adamc@281 820 int len;
adamc@281 821 char *r;
adamc@281 822
adamc@311 823 uw_check_heap(ctx, INTS_MAX + 6);
adamc@281 824 r = ctx->heap_front;
adamc@281 825 sprintf(r, "%lld::int8%n", n, &len);
adamc@281 826 ctx->heap_front += len+1;
adamc@281 827 return r;
adamc@281 828 }
adamc@281 829
adamc@311 830 char *uw_Basis_sqlifyFloat(uw_context ctx, uw_Basis_float n) {
adamc@281 831 int len;
adamc@281 832 char *r;
adamc@281 833
adamc@311 834 uw_check_heap(ctx, FLOATS_MAX + 8);
adamc@281 835 r = ctx->heap_front;
adamc@281 836 sprintf(r, "%g::float8%n", n, &len);
adamc@281 837 ctx->heap_front += len+1;
adamc@281 838 return r;
adamc@281 839 }
adamc@281 840
adamc@281 841
adamc@311 842 uw_Basis_string uw_Basis_sqlifyString(uw_context ctx, uw_Basis_string s) {
adamc@280 843 char *r, *s2;
adamc@280 844
adamc@311 845 uw_check_heap(ctx, strlen(s) * 2 + 10);
adamc@280 846
adamc@280 847 r = s2 = ctx->heap_front;
adamc@280 848 *s2++ = 'E';
adamc@280 849 *s2++ = '\'';
adamc@280 850
adamc@280 851 for (; *s; s++) {
adamc@280 852 char c = *s;
adamc@280 853
adamc@280 854 switch (c) {
adamc@280 855 case '\'':
adamc@280 856 strcpy(s2, "\\'");
adamc@280 857 s2 += 2;
adamc@280 858 break;
adamc@280 859 case '\\':
adamc@280 860 strcpy(s2, "\\\\");
adamc@280 861 s2 += 2;
adamc@280 862 break;
adamc@280 863 default:
adamc@280 864 if (isprint(c))
adamc@280 865 *s2++ = c;
adamc@280 866 else {
adamc@280 867 sprintf(s2, "\\%3o", c);
adamc@280 868 s2 += 4;
adamc@280 869 }
adamc@280 870 }
adamc@280 871 }
adamc@280 872
adamc@281 873 strcpy(s2, "'::text");
adamc@281 874 ctx->heap_front = s2 + 8;
adamc@280 875 return r;
adamc@280 876 }
adamc@281 877
adamc@311 878 char *uw_Basis_sqlifyBool(uw_context ctx, uw_Basis_bool b) {
adamc@311 879 if (b == uw_Basis_False)
adamc@281 880 return "FALSE";
adamc@281 881 else
adamc@281 882 return "TRUE";
adamc@281 883 }
adamc@282 884
adamc@439 885 char *uw_Basis_sqlifyTime(uw_context ctx, uw_Basis_time t) {
adamc@439 886 size_t len;
adamc@439 887 char *r;
adamc@439 888 struct tm stm;
adamc@439 889
adamc@439 890 if (localtime_r(&t, &stm)) {
adamc@439 891 uw_check_heap(ctx, TIMES_MAX);
adamc@439 892 r = ctx->heap_front;
adamc@439 893 len = strftime(r, TIMES_MAX, TIME_FMT, &stm);
adamc@439 894 ctx->heap_front += len+1;
adamc@439 895 return r;
adamc@439 896 } else
adamc@439 897 return "<Invalid time>";
adamc@439 898 }
adamc@439 899
adamc@311 900 char *uw_Basis_ensqlBool(uw_Basis_bool b) {
adamc@311 901 static uw_Basis_int true = 1;
adamc@311 902 static uw_Basis_int false = 0;
adamc@282 903
adamc@311 904 if (b == uw_Basis_False)
adamc@282 905 return (char *)&false;
adamc@282 906 else
adamc@282 907 return (char *)&true;
adamc@282 908 }
adamc@284 909
adamc@311 910 uw_Basis_string uw_Basis_intToString(uw_context ctx, uw_Basis_int n) {
adamc@284 911 int len;
adamc@284 912 char *r;
adamc@284 913
adamc@311 914 uw_check_heap(ctx, INTS_MAX);
adamc@284 915 r = ctx->heap_front;
adamc@284 916 sprintf(r, "%lld%n", n, &len);
adamc@284 917 ctx->heap_front += len+1;
adamc@284 918 return r;
adamc@284 919 }
adamc@285 920
adamc@311 921 uw_Basis_string uw_Basis_floatToString(uw_context ctx, uw_Basis_float n) {
adamc@285 922 int len;
adamc@285 923 char *r;
adamc@285 924
adamc@311 925 uw_check_heap(ctx, FLOATS_MAX);
adamc@285 926 r = ctx->heap_front;
adamc@285 927 sprintf(r, "%g%n", n, &len);
adamc@285 928 ctx->heap_front += len+1;
adamc@285 929 return r;
adamc@285 930 }
adamc@285 931
adamc@311 932 uw_Basis_string uw_Basis_boolToString(uw_context ctx, uw_Basis_bool b) {
adamc@311 933 if (b == uw_Basis_False)
adamc@285 934 return "False";
adamc@285 935 else
adamc@285 936 return "True";
adamc@285 937 }
adamc@288 938
adamc@436 939 uw_Basis_string uw_Basis_timeToString(uw_context ctx, uw_Basis_time t) {
adamc@436 940 size_t len;
adamc@436 941 char *r;
adamc@436 942 struct tm stm;
adamc@436 943
adamc@436 944 if (localtime_r(&t, &stm)) {
adamc@436 945 uw_check_heap(ctx, TIMES_MAX);
adamc@436 946 r = ctx->heap_front;
adamc@436 947 len = strftime(r, TIMES_MAX, TIME_FMT, &stm);
adamc@436 948 ctx->heap_front += len+1;
adamc@436 949 return r;
adamc@436 950 } else
adamc@436 951 return "<Invalid time>";
adamc@436 952 }
adamc@288 953
adamc@311 954 uw_Basis_int *uw_Basis_stringToInt(uw_context ctx, uw_Basis_string s) {
adamc@288 955 char *endptr;
adamc@311 956 uw_Basis_int n = strtoll(s, &endptr, 10);
adamc@288 957
adamc@288 958 if (*s != '\0' && *endptr == '\0') {
adamc@311 959 uw_Basis_int *r = uw_malloc(ctx, sizeof(uw_Basis_int));
adamc@288 960 *r = n;
adamc@288 961 return r;
adamc@288 962 } else
adamc@288 963 return NULL;
adamc@288 964 }
adamc@289 965
adamc@311 966 uw_Basis_float *uw_Basis_stringToFloat(uw_context ctx, uw_Basis_string s) {
adamc@289 967 char *endptr;
adamc@311 968 uw_Basis_float n = strtod(s, &endptr);
adamc@289 969
adamc@289 970 if (*s != '\0' && *endptr == '\0') {
adamc@311 971 uw_Basis_float *r = uw_malloc(ctx, sizeof(uw_Basis_float));
adamc@289 972 *r = n;
adamc@289 973 return r;
adamc@289 974 } else
adamc@289 975 return NULL;
adamc@289 976 }
adamc@289 977
adamc@311 978 uw_Basis_bool *uw_Basis_stringToBool(uw_context ctx, uw_Basis_string s) {
adamc@311 979 static uw_Basis_bool true = uw_Basis_True;
adamc@311 980 static uw_Basis_bool false = uw_Basis_False;
adamc@289 981
adamc@289 982 if (!strcasecmp (s, "True"))
adamc@289 983 return &true;
adamc@289 984 else if (!strcasecmp (s, "False"))
adamc@289 985 return &false;
adamc@289 986 else
adamc@289 987 return NULL;
adamc@289 988 }
adamc@292 989
adamc@436 990 uw_Basis_time *uw_Basis_stringToTime(uw_context ctx, uw_Basis_string s) {
adamc@438 991 char *dot = strchr(s, '.'), *end = strchr(s, 0);
adamc@436 992 struct tm stm;
adamc@436 993
adamc@439 994 if (dot) {
adamc@439 995 *dot = 0;
adamc@439 996 if (strptime(s, TIME_FMT_PG, &stm) == end) {
adamc@439 997 *dot = '.';
adamc@439 998 uw_Basis_time *r = uw_malloc(ctx, sizeof(uw_Basis_time));
adamc@439 999 *r = mktime(&stm);
adamc@439 1000 return r;
adamc@439 1001 }
adamc@439 1002 else {
adamc@439 1003 *dot = '.';
adamc@439 1004 return NULL;
adamc@439 1005 }
adamc@436 1006 }
adamc@439 1007 else {
adamc@439 1008 if (strptime(s, TIME_FMT_PG, &stm) == end) {
adamc@439 1009 uw_Basis_time *r = uw_malloc(ctx, sizeof(uw_Basis_time));
adamc@439 1010 *r = mktime(&stm);
adamc@439 1011 return r;
adamc@439 1012 }
adamc@439 1013 else if (strptime(s, TIME_FMT, &stm) == end) {
adamc@439 1014 uw_Basis_time *r = uw_malloc(ctx, sizeof(uw_Basis_time));
adamc@439 1015 *r = mktime(&stm);
adamc@439 1016 return r;
adamc@439 1017 }
adamc@439 1018 else
adamc@439 1019 return NULL;
adamc@439 1020 }
adamc@436 1021 }
adamc@436 1022
adamc@311 1023 uw_Basis_int uw_Basis_stringToInt_error(uw_context ctx, uw_Basis_string s) {
adamc@292 1024 char *endptr;
adamc@311 1025 uw_Basis_int n = strtoll(s, &endptr, 10);
adamc@292 1026
adamc@292 1027 if (*s != '\0' && *endptr == '\0')
adamc@292 1028 return n;
adamc@292 1029 else
adamc@311 1030 uw_error(ctx, FATAL, "Can't parse int: %s", s);
adamc@292 1031 }
adamc@293 1032
adamc@311 1033 uw_Basis_float uw_Basis_stringToFloat_error(uw_context ctx, uw_Basis_string s) {
adamc@293 1034 char *endptr;
adamc@311 1035 uw_Basis_float n = strtod(s, &endptr);
adamc@293 1036
adamc@293 1037 if (*s != '\0' && *endptr == '\0')
adamc@293 1038 return n;
adamc@293 1039 else
adamc@311 1040 uw_error(ctx, FATAL, "Can't parse float: %s", s);
adamc@293 1041 }
adamc@293 1042
adamc@311 1043 uw_Basis_bool uw_Basis_stringToBool_error(uw_context ctx, uw_Basis_string s) {
adamc@296 1044 if (!strcasecmp(s, "T") || !strcasecmp (s, "True"))
adamc@311 1045 return uw_Basis_True;
adamc@296 1046 else if (!strcasecmp(s, "F") || !strcasecmp (s, "False"))
adamc@311 1047 return uw_Basis_False;
adamc@293 1048 else
adamc@311 1049 uw_error(ctx, FATAL, "Can't parse bool: %s", s);
adamc@293 1050 }
adamc@436 1051
adamc@436 1052 uw_Basis_time uw_Basis_stringToTime_error(uw_context ctx, uw_Basis_string s) {
adamc@438 1053 char *dot = strchr(s, '.'), *end = strchr(s, 0);
adamc@436 1054 struct tm stm = {};
adamc@436 1055
adamc@438 1056 if (dot) {
adamc@438 1057 *dot = 0;
adamc@438 1058 if (strptime(s, TIME_FMT_PG, &stm)) {
adamc@438 1059 *dot = '.';
adamc@438 1060 return mktime(&stm);
adamc@438 1061 }
adamc@438 1062 else {
adamc@438 1063 *dot = '.';
adamc@438 1064 uw_error(ctx, FATAL, "Can't parse time: %s", s);
adamc@438 1065 }
adamc@438 1066 }
adamc@438 1067 else {
adamc@439 1068 if (strptime(s, TIME_FMT_PG, &stm) == end)
adamc@439 1069 return mktime(&stm);
adamc@439 1070 else if (strptime(s, TIME_FMT, &stm) == end)
adamc@438 1071 return mktime(&stm);
adamc@438 1072 else
adamc@438 1073 uw_error(ctx, FATAL, "Can't parse time: %s", s);
adamc@438 1074 }
adamc@436 1075 }
adamc@457 1076
adamc@457 1077 uw_Basis_string uw_Basis_requestHeader(uw_context ctx, uw_Basis_string h) {
adamc@457 1078 int len = strlen(h);
adamc@457 1079 char *s = ctx->headers, *p;
adamc@457 1080
adamc@457 1081 while (p = strchr(s, ':')) {
adamc@457 1082 if (p - s == len && !strncasecmp(s, h, len)) {
adamc@458 1083 return p + 2;
adamc@457 1084 } else {
adamc@458 1085 if ((s = strchr(p, 0)) && s < ctx->headers_end)
adamc@458 1086 s += 2;
adamc@457 1087 else
adamc@457 1088 return NULL;
adamc@457 1089 }
adamc@457 1090 }
adamc@458 1091
adamc@457 1092 }