annotate src/c/urweb.c @ 272:4d80d6122df1

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