annotate src/c/urweb.c @ 448:85819353a84f

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