@@ -285,19 +285,27 @@ VAL MKSTR(VM* vm, const char* str) {
285285 Closure* cl = allocate(sizeof(Closure) + // Type) + sizeof(char*) +
286286 sizeof(char)*len, 0);
287287 SETTY(cl, CT_STRING);
288− cl -> info.str = (char*)cl + sizeof(Closure);
288+ cl->info.str.str = (char*)cl + sizeof(Closure);
289289 if (str == NULL) {
290− cl->info.str = NULL;
290+ cl->info.str.str = NULL;
291291 } else {
292− strcpy(cl -> info.str, str);
292+ strcpy(cl->info.str.str, str);
293293 }
294+ cl->info.str.len = len > 0 ? len : 0;
294295 return cl;
295296}
296297
297298char* GETSTROFF(VAL stroff) {
298299 // Assume STROFF
299300 StrOffset* root = stroff->info.str_offset;
300− return (root->str->info.str + root->offset);
301+ return (root->str->info.str.str + root->offset);
302+}
303+
304+size_t GETSTROFFLEN(VAL stroff) {
305+ // Assume STROFF
306+ // we're working in char* here so no worries about utf8 char length
307+ StrOffset* root = stroff->info.str_offset;
308+ return (root->str->info.str.len - root->offset);
301309}
302310
303311VAL MKCDATA(VM* vm, CHeapItem * item) {
@@ -342,12 +350,26 @@ VAL MKFLOATc(VM* vm, double val) {
342350}
343351
344352VAL MKSTRc(VM* vm, char* str) {
353+ int len = strlen(str);
354+
355+ Closure* cl = allocate(sizeof(Closure) + // Type) + sizeof(char*) +
356+ sizeof(char)*len+1, 1);
357+ SETTY(cl, CT_STRING);
358+ cl -> info.str.str = (char*)cl + sizeof(Closure);
359+
360+ strcpy(cl->info.str.str, str);
361+ cl->info.str.len = len;
362+ return cl;
363+}
364+
365+VAL MKSTRclen(VM* vm, char* str, int len) {
345366 Closure* cl = allocate(sizeof(Closure) + // Type) + sizeof(char*) +
346− sizeof(char)*strlen(str)+1, 1);
367+ sizeof(char)*len+1, 1);
347368 SETTY(cl, CT_STRING);
348− cl -> info.str = (char*)cl + sizeof(Closure);
369+ cl -> info.str.str = (char*)cl + sizeof(Closure);
349370
350− strcpy(cl -> info.str, str);
371+ strcpy(cl->info.str.str, str);
372+ cl->info.str.len = len;
351373 return cl;
352374}
353375
@@ -428,7 +450,7 @@ void dumpVal(VAL v) {
428450 printf("] ");
429451 break;
430452 case CT_STRING:
431− printf("STR[%s]", v->info.str);
453+ printf("STR[%s]", v->info.str.str);
432454 break;
433455 case CT_FWD:
434456 printf("CT_FWD ");
@@ -490,8 +512,9 @@ VAL idris_castIntStr(VM* vm, VAL i) {
490512 int x = (int) GETINT(i);
491513 Closure* cl = allocate(sizeof(Closure) + sizeof(char)*16, 0);
492514 SETTY(cl, CT_STRING);
493− cl -> info.str = (char*)cl + sizeof(Closure);
494− sprintf(cl -> info.str, "%d", x);
515+ cl->info.str.str = (char*)cl + sizeof(Closure);
516+ sprintf(cl->info.str.str, "%d", x);
517+ cl->info.str.len = strlen(cl->info.str.str);
495518 return cl;
496519}
497520
@@ -503,32 +526,33 @@ VAL idris_castBitsStr(VM* vm, VAL i) {
503526 case CT_BITS8:
504527 // max length 8 bit unsigned int str 3 chars (256)
505528 cl = allocate(sizeof(Closure) + sizeof(char)*4, 0);
506− cl->info.str = (char*)cl + sizeof(Closure);
507− sprintf(cl->info.str, "%" PRIu8, (uint8_t)i->info.bits8);
529+ cl->info.str.str = (char*)cl + sizeof(Closure);
530+ sprintf(cl->info.str.str, "%" PRIu8, (uint8_t)i->info.bits8);
508531 break;
509532 case CT_BITS16:
510533 // max length 16 bit unsigned int str 5 chars (65,535)
511534 cl = allocate(sizeof(Closure) + sizeof(char)*6, 0);
512− cl->info.str = (char*)cl + sizeof(Closure);
513− sprintf(cl->info.str, "%" PRIu16, (uint16_t)i->info.bits16);
535+ cl->info.str.str = (char*)cl + sizeof(Closure);
536+ sprintf(cl->info.str.str, "%" PRIu16, (uint16_t)i->info.bits16);
514537 break;
515538 case CT_BITS32:
516539 // max length 32 bit unsigned int str 10 chars (4,294,967,295)
517540 cl = allocate(sizeof(Closure) + sizeof(char)*11, 0);
518− cl->info.str = (char*)cl + sizeof(Closure);
519− sprintf(cl->info.str, "%" PRIu32, (uint32_t)i->info.bits32);
541+ cl->info.str.str = (char*)cl + sizeof(Closure);
542+ sprintf(cl->info.str.str, "%" PRIu32, (uint32_t)i->info.bits32);
520543 break;
521544 case CT_BITS64:
522545 // max length 64 bit unsigned int str 20 chars (18,446,744,073,709,551,615)
523546 cl = allocate(sizeof(Closure) + sizeof(char)*21, 0);
524− cl->info.str = (char*)cl + sizeof(Closure);
525− sprintf(cl->info.str, "%" PRIu64, (uint64_t)i->info.bits64);
547+ cl->info.str.str = (char*)cl + sizeof(Closure);
548+ sprintf(cl->info.str.str, "%" PRIu64, (uint64_t)i->info.bits64);
526549 break;
527550 default:
528551 fprintf(stderr, "Fatal Error: ClosureType %d, not an integer type", ty);
529552 exit(EXIT_FAILURE);
530553 }
531554
555+ cl->info.str.len = strlen(cl->info.str.str);
532556 SETTY(cl, CT_STRING);
533557 return cl;
534558}
@@ -545,8 +569,10 @@ VAL idris_castStrInt(VM* vm, VAL i) {
545569VAL idris_castFloatStr(VM* vm, VAL i) {
546570 Closure* cl = allocate(sizeof(Closure) + sizeof(char)*32, 0);
547571 SETTY(cl, CT_STRING);
548− cl -> info.str = (char*)cl + sizeof(Closure);
549− snprintf(cl -> info.str, 32, "%.16g", GETFLOAT(i));
572+ cl->info.str.str = (char*)cl + sizeof(Closure);
573+ snprintf(cl->info.str.str, 32, "%.16g", GETFLOAT(i));
574+
575+ cl->info.str.len = strlen(cl->info.str.str);
550576 return cl;
551577}
552578
@@ -559,11 +585,13 @@ VAL idris_concat(VM* vm, VAL l, VAL r) {
559585 char *ls = GETSTR(l);
560586 // dumpVal(l);
561587 // printf("\n");
562− Closure* cl = allocate(sizeof(Closure) + strlen(ls) + strlen(rs) + 1, 0);
588+ Closure* cl = allocate(sizeof(Closure) + GETSTRLEN(l) + GETSTRLEN(r) + 1, 0);
563589 SETTY(cl, CT_STRING);
564− cl -> info.str = (char*)cl + sizeof(Closure);
565− strcpy(cl -> info.str, ls);
566− strcat(cl -> info.str, rs);
590+ cl->info.str.str = (char*)cl + sizeof(Closure);
591+ strcpy(cl->info.str.str, ls);
592+ strcat(cl->info.str.str, rs);
593+
594+ cl->info.str.len = GETSTRLEN(l) + GETSTRLEN(r);
567595 return cl;
568596}
569597
@@ -670,21 +698,26 @@ VAL idris_strTail(VM* vm, VAL str) {
670698VAL idris_strCons(VM* vm, VAL x, VAL xs) {
671699 char *xstr = GETSTR(xs);
672700 int xval = GETINT(x);
701+ int xlen = GETSTRLEN(xs);
702+
673703 if ((xval & 0x80) == 0) { // ASCII char
674704 Closure* cl = allocate(sizeof(Closure) +
675− strlen(xstr) + 2, 0);
705+ xlen + 2, 0);
676706 SETTY(cl, CT_STRING);
677− cl -> info.str = (char*)cl + sizeof(Closure);
678− cl -> info.str[0] = (char)(GETINT(x));
679− strcpy(cl -> info.str+1, xstr);
707+ cl->info.str.str = (char*)cl + sizeof(Closure);
708+ cl->info.str.str[0] = (char)(GETINT(x));
709+ strcpy(cl->info.str.str+1, xstr);
710+ cl->info.str.len = xlen + 1;
680711 return cl;
681712 } else {
682713 char *init = idris_utf8_fromChar(xval);
683− Closure* cl = allocate(sizeof(Closure) + strlen(init) + strlen(xstr) + 1, 0);
714+ int newlen = strlen(init) + xlen;
715+ Closure* cl = allocate(sizeof(Closure) + newlen + 1, 0);
684716 SETTY(cl, CT_STRING);
685− cl -> info.str = (char*)cl + sizeof(Closure);
686− strcpy(cl -> info.str, init);
687− strcat(cl -> info.str, xstr);
717+ cl->info.str.str = (char*)cl + sizeof(Closure);
718+ strcpy(cl->info.str.str, init);
719+ strcat(cl->info.str.str, xstr);
720+ cl->info.str.len = newlen;
688721 free(init);
689722 return cl;
690723 }
@@ -701,7 +734,7 @@ VAL idris_substr(VM* vm, VAL offset, VAL length, VAL str) {
701734 char* str_val = GETSTR(str);
702735
703736 // If the substring is a suffix, use idris_strShift to avoid reallocating
704− if (offset_val + length_val >= strlen(str_val)) {
737+ if (offset_val + length_val >= GETSTRLEN(str)) {
705738 return idris_strShift(vm, str, offset_val);
706739 }
707740 else {
@@ -709,20 +742,23 @@ VAL idris_substr(VM* vm, VAL offset, VAL length, VAL str) {
709742 char *end = idris_utf8_advance(start, length_val);
710743 Closure* newstr = allocate(sizeof(Closure) + (end - start) +1, 0);
711744 SETTY(newstr, CT_STRING);
712− newstr -> info.str = (char*)newstr + sizeof(Closure);
713− memcpy(newstr -> info.str, start, end - start);
714− *(newstr -> info.str + (end - start) + 1) = '\0';
745+ newstr->info.str.str = (char*)newstr + sizeof(Closure);
746+ memcpy(newstr->info.str.str, start, end - start);
747+ *(newstr->info.str.str + (end - start) + 1) = '\0';
748+ newstr->info.str.len = strlen(newstr->info.str.str);
715749 return newstr;
716750 }
717751}
718752
719753VAL idris_strRev(VM* vm, VAL str) {
720754 char *xstr = GETSTR(str);
721− Closure* cl = allocate(sizeof(Closure) +
722− strlen(xstr) + 1, 0);
755+ int xlen = GETSTRLEN(str);
756+
757+ Closure* cl = allocate(sizeof(Closure) + xlen + 1, 0);
723758 SETTY(cl, CT_STRING);
724− cl->info.str = (char*)cl + sizeof(Closure);
725− idris_utf8_rev(xstr, cl->info.str);
759+ cl->info.str.str = (char*)cl + sizeof(Closure);
760+ cl->info.str.len = xlen;
761+ idris_utf8_rev(xstr, cl->info.str.str);
726762 return cl;
727763}
728764
@@ -832,7 +868,7 @@ VAL doCopyTo(VM* vm, VAL x) {
832868 cl = MKFLOATc(vm, x->info.f);
833869 break;
834870 case CT_STRING:
835− cl = MKSTRc(vm, x->info.str);
871+ cl = MKSTRc(vm, x->info.str.str);
836872 break;
837873 case CT_BIGINT:
838874 cl = MKBIGMc(vm, x->info.ptr);