annotate src/c/lacweb.c @ 186:88d46972de53

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