1 /* Native functions. 2 3 Copyright (C) 2016 Paul Boddie <paul@boddie.org.uk> 4 5 This program is free software; you can redistribute it and/or modify it under 6 the terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 3 of the License, or (at your option) any later 8 version. 9 10 This program is distributed in the hope that it will be useful, but WITHOUT 11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 13 details. 14 15 You should have received a copy of the GNU General Public License along with 16 this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include <stdlib.h> /* abs, exit */ 20 #include <unistd.h> /* read, write */ 21 #include <limits.h> /* INT_MAX, INT_MIN */ 22 #include <math.h> /* ceil, log10, pow */ 23 #include <string.h> /* strcmp, strncpy, strlen */ 24 #include <stdio.h> /* fdopen, snprintf */ 25 #include <errno.h> /* errno */ 26 #include "types.h" 27 #include "exceptions.h" 28 #include "ops.h" 29 #include "progconsts.h" 30 #include "progops.h" 31 #include "progtypes.h" 32 #include "main.h" 33 34 /* Utility functions. */ 35 36 static __attr __new_int(int i) 37 { 38 /* Create a new integer and mutate the __data__ attribute. */ 39 __attr attr = __new(&__InstanceTable___builtins___int_int, &__builtins___int_int, sizeof(__obj___builtins___int_int)); 40 attr.value->attrs[__pos___data__].intvalue = i; 41 return attr; 42 } 43 44 static __attr __new_str(char *s) 45 { 46 /* Create a new string and mutate the __data__ attribute. */ 47 __attr attr = __new(&__InstanceTable___builtins___str_string, &__builtins___str_string, sizeof(__obj___builtins___str_string)); 48 attr.value->attrs[__pos___data__].strvalue = s; 49 return attr; 50 } 51 52 static __attr __new_list(__fragment *f) 53 { 54 /* Create a new list and mutate the __data__ attribute. */ 55 __attr attr = __new(&__InstanceTable___builtins___list_list, &__builtins___list_list, sizeof(__obj___builtins___list_list)); 56 attr.value->attrs[__pos___data__].seqvalue = f; 57 return attr; 58 } 59 60 static __fragment *__fragment_append(__fragment *data, __attr * const value) 61 { 62 __fragment *newdata = data; 63 unsigned int size = data->size, capacity = data->capacity; 64 unsigned int n; 65 66 /* Re-allocate the fragment if the capacity has been reached. */ 67 if (size >= capacity) 68 { 69 /* NOTE: Consider various restrictions on capacity increases. */ 70 n = capacity ? capacity * 2 : 1; 71 newdata = (__fragment *) __REALLOCATE(data, __FRAGMENT_SIZE(n)); 72 newdata->capacity = n; 73 } 74 75 /* Insert the new element and increment the list size. */ 76 newdata->attrs[size] = *value; 77 newdata->size = size + 1; 78 79 return newdata; 80 } 81 82 /* Environment support. */ 83 84 __attr __fn_native__exit(__attr __args[]) 85 { 86 __attr * const status = &__args[1]; 87 88 exit(__load_via_object(status->value, __pos___data__).intvalue); 89 return __builtins___none_None; 90 } 91 92 __attr __fn_native__get_argv(__attr __args[]) 93 { 94 __attr * const status = &__args[1]; 95 96 /* NOTE: To be written. */ 97 return __builtins___none_None; 98 } 99 100 __attr __fn_native__get_path(__attr __args[]) 101 { 102 __attr * const status = &__args[1]; 103 104 /* NOTE: To be written. */ 105 return __builtins___none_None; 106 } 107 108 /* Identity testing. */ 109 110 __attr __fn_native__is(__attr __args[]) 111 { 112 __attr * const x = &__args[1]; 113 __attr * const y = &__args[2]; 114 115 return x->value == y->value ? __builtins___boolean_True : __builtins___boolean_False; 116 } 117 118 __attr __fn_native__is_not(__attr __args[]) 119 { 120 __attr * const x = &__args[1]; 121 __attr * const y = &__args[2]; 122 123 return x->value != y->value ? __builtins___boolean_True : __builtins___boolean_False; 124 } 125 126 /* Limit definition. */ 127 128 __attr __fn_native__get_maxint(__attr __args[]) 129 { 130 __attr * const status = &__args[1]; 131 132 return __new_int(INT_MAX); 133 } 134 135 __attr __fn_native__get_minint(__attr __args[]) 136 { 137 __attr * const status = &__args[1]; 138 139 return __new_int(INT_MIN); 140 } 141 142 /* Integer operations. */ 143 144 __attr __fn_native__int_add(__attr __args[]) 145 { 146 __attr * const _data = &__args[1]; 147 __attr * const other = &__args[2]; 148 /* _data and other interpreted as int */ 149 int i = _data->intvalue; 150 int j = other->intvalue; 151 152 /* Test for overflow. */ 153 if (((i > 0) && (j > 0) && (i > INT_MAX - j)) || 154 ((i < 0) && (j < 0) && (i < INT_MIN - j))) 155 156 __raise_overflow_error(); 157 158 /* Return the new integer. */ 159 return __new_int(i + j); 160 } 161 162 __attr __fn_native__int_sub(__attr __args[]) 163 { 164 __attr * const _data = &__args[1]; 165 __attr * const other = &__args[2]; 166 /* _data and other interpreted as int */ 167 int i = _data->intvalue; 168 int j = other->intvalue; 169 170 /* Test for overflow. */ 171 if (((i < 0) && (j > 0) && (i < INT_MIN + j)) || 172 ((i > 0) && (j < 0) && (i > INT_MAX + j))) 173 174 __raise_overflow_error(); 175 176 /* Return the new integer. */ 177 return __new_int(i - j); 178 } 179 180 __attr __fn_native__int_mul(__attr __args[]) 181 { 182 __attr * const _data = &__args[1]; 183 __attr * const other = &__args[2]; 184 /* _data and other interpreted as int */ 185 int i = _data->intvalue; 186 int j = other->intvalue; 187 188 /* Test for overflow. */ 189 if (((i > 0) && (j > 0) && (i > INT_MAX / j)) || 190 ((i < 0) && (j < 0) && (i > INT_MAX / j)) || 191 ((i < 0) && (j > 0) && (i < INT_MIN / j)) || 192 ((i > 0) && (j < 0) && (j < INT_MIN / i))) 193 194 __raise_overflow_error(); 195 196 /* Return the new integer. */ 197 return __new_int(i * j); 198 } 199 200 __attr __fn_native__int_div(__attr __args[]) 201 { 202 __attr * const _data = &__args[1]; 203 __attr * const other = &__args[2]; 204 /* _data and other interpreted as int */ 205 int i = _data->intvalue; 206 int j = other->intvalue; 207 208 /* Test for division by zero or overflow. */ 209 if (j == 0) 210 __raise_zero_division_error(); 211 else if ((j == -1) && (i == INT_MIN)) 212 __raise_overflow_error(); 213 214 /* Return the new integer. */ 215 return __new_int(i / j); 216 } 217 218 __attr __fn_native__int_mod(__attr __args[]) 219 { 220 __attr * const _data = &__args[1]; 221 __attr * const other = &__args[2]; 222 /* _data and other interpreted as int */ 223 int i = _data->intvalue; 224 int j = other->intvalue; 225 226 /* Test for division by zero or overflow. */ 227 if (j == 0) 228 __raise_zero_division_error(); 229 else if ((j == -1) && (i == INT_MIN)) 230 __raise_overflow_error(); 231 232 /* Return the new integer. */ 233 return __new_int(i % j); 234 } 235 236 __attr __fn_native__int_neg(__attr __args[]) 237 { 238 __attr * const _data = &__args[1]; 239 /* _data interpreted as int */ 240 int i = _data->intvalue; 241 242 /* Test for overflow. */ 243 if (i == INT_MIN) 244 __raise_overflow_error(); 245 246 /* Return the new integer. */ 247 return __new_int(-i); 248 } 249 250 __attr __fn_native__int_pow(__attr __args[]) 251 { 252 __attr * const _data = &__args[1]; 253 __attr * const other = &__args[2]; 254 /* _data and other interpreted as int */ 255 int i = _data->intvalue; 256 int j = other->intvalue; 257 int k; 258 259 errno = 0; 260 k = (int) pow(i, j); 261 262 /* Test for overflow. */ 263 264 if (errno == ERANGE) 265 __raise_overflow_error(); 266 267 /* Return the new integer. */ 268 return __new_int(k); 269 } 270 271 __attr __fn_native__int_and(__attr __args[]) 272 { 273 __attr * const _data = &__args[1]; 274 __attr * const other = &__args[2]; 275 /* _data and other interpreted as int */ 276 int i = _data->intvalue; 277 int j = other->intvalue; 278 279 /* Return the new integer. */ 280 /* NOTE: No overflow test applied. */ 281 return __new_int(i & j); 282 } 283 284 __attr __fn_native__int_not(__attr __args[]) 285 { 286 __attr * const _data = &__args[1]; 287 /* _data interpreted as int */ 288 int i = _data->intvalue; 289 290 /* Return the new integer. */ 291 return __new_int(~i); 292 } 293 294 __attr __fn_native__int_or(__attr __args[]) 295 { 296 __attr * const _data = &__args[1]; 297 __attr * const other = &__args[2]; 298 /* _data and other interpreted as int */ 299 int i = _data->intvalue; 300 int j = other->intvalue; 301 302 /* Return the new integer. */ 303 /* NOTE: No overflow test applied. */ 304 return __new_int(i | j); 305 } 306 307 __attr __fn_native__int_xor(__attr __args[]) 308 { 309 __attr * const _data = &__args[1]; 310 __attr * const other = &__args[2]; 311 /* _data and other interpreted as int */ 312 int i = _data->intvalue; 313 int j = other->intvalue; 314 315 /* Return the new integer. */ 316 /* NOTE: No overflow test applied. */ 317 return __new_int(i ^ j); 318 } 319 320 __attr __fn_native__int_lt(__attr __args[]) 321 { 322 __attr * const _data = &__args[1]; 323 __attr * const other = &__args[2]; 324 /* _data and other interpreted as int */ 325 int i = _data->intvalue; 326 int j = other->intvalue; 327 328 /* Return a boolean result. */ 329 return i < j ? __builtins___boolean_True : __builtins___boolean_False; 330 } 331 332 __attr __fn_native__int_gt(__attr __args[]) 333 { 334 __attr * const _data = &__args[1]; 335 __attr * const other = &__args[2]; 336 /* _data and other interpreted as int */ 337 int i = _data->intvalue; 338 int j = other->intvalue; 339 340 /* Return a boolean result. */ 341 return i > j ? __builtins___boolean_True : __builtins___boolean_False; 342 } 343 344 __attr __fn_native__int_eq(__attr __args[]) 345 { 346 __attr * const _data = &__args[1]; 347 __attr * const other = &__args[2]; 348 /* _data and other interpreted as int */ 349 int i = _data->intvalue; 350 int j = other->intvalue; 351 352 /* Return a boolean result. */ 353 return i == j ? __builtins___boolean_True : __builtins___boolean_False; 354 } 355 356 __attr __fn_native__int_ne(__attr __args[]) 357 { 358 __attr * const _data = &__args[1]; 359 __attr * const other = &__args[2]; 360 /* _data and other interpreted as int */ 361 int i = _data->intvalue; 362 int j = other->intvalue; 363 364 /* Return a boolean result. */ 365 return i != j ? __builtins___boolean_True : __builtins___boolean_False; 366 } 367 368 __attr __fn_native__int_str(__attr __args[]) 369 { 370 __attr * const _data = &__args[1]; 371 /* _data interpreted as int */ 372 int i = _data->intvalue; 373 /* Employ a buffer big enough to fit the largest integer plus an extra 374 character, a minus sign, and the null terminator. */ 375 unsigned int n = (int) log10(INT_MAX) + 3; 376 char *s = (char *) __ALLOCATE(n, sizeof(char)); 377 378 snprintf(s, n, "%d", i); 379 380 /* Return a new string. */ 381 return __new_str(s); 382 } 383 384 /* String operations. */ 385 386 __attr __fn_native__str_add(__attr __args[]) 387 { 388 __attr * const _data = &__args[1]; 389 __attr * const other = &__args[2]; 390 /* _data, other interpreted as string */ 391 char *s = _data->strvalue; 392 char *o = other->strvalue; 393 int n = strlen(s) + strlen(o) + 1; 394 char *r = (char *) __ALLOCATE(n, sizeof(char)); 395 396 strncpy(r, s, n); 397 strncpy(r + strlen(s), o, n - strlen(s)); /* should null terminate */ 398 399 /* Return a new string. */ 400 return __new_str(r); 401 } 402 403 __attr __fn_native__str_lt(__attr __args[]) 404 { 405 __attr * const _data = &__args[1]; 406 __attr * const other = &__args[2]; 407 /* _data, other interpreted as string */ 408 char *s = _data->strvalue; 409 char *o = other->strvalue; 410 411 /* NOTE: Using simple byte-level string operations. */ 412 return strcmp(s, o) < 0 ? __builtins___boolean_True : __builtins___boolean_False; 413 } 414 415 __attr __fn_native__str_gt(__attr __args[]) 416 { 417 __attr * const _data = &__args[1]; 418 __attr * const other = &__args[2]; 419 /* _data, other interpreted as string */ 420 char *s = _data->strvalue; 421 char *o = other->strvalue; 422 423 /* NOTE: Using simple byte-level string operations. */ 424 return strcmp(s, o) > 0 ? __builtins___boolean_True : __builtins___boolean_False; 425 } 426 427 __attr __fn_native__str_eq(__attr __args[]) 428 { 429 __attr * const _data = &__args[1]; 430 __attr * const other = &__args[2]; 431 /* _data, other interpreted as string */ 432 char *s = _data->strvalue; 433 char *o = other->strvalue; 434 435 /* NOTE: Using simple byte-level string operations. */ 436 return strcmp(s, o) == 0 ? __builtins___boolean_True : __builtins___boolean_False; 437 } 438 439 __attr __fn_native__str_len(__attr __args[]) 440 { 441 __attr * const _data = &__args[1]; 442 /* _data interpreted as string */ 443 char *s = _data->strvalue; 444 445 /* Return the new integer. */ 446 return __new_int(strlen(s)); 447 } 448 449 __attr __fn_native__str_nonempty(__attr __args[]) 450 { 451 __attr * const _data = &__args[1]; 452 /* _data interpreted as string */ 453 char *s = _data->strvalue; 454 455 return strlen(s) ? __builtins___boolean_True : __builtins___boolean_False; 456 } 457 458 __attr __fn_native__str_ord(__attr __args[]) 459 { 460 __attr * const _data = &__args[1]; 461 /* _data interpreted as string */ 462 char *s = _data->strvalue; 463 464 return __new_int((unsigned int) s[0]); 465 } 466 467 __attr __fn_native__str_substr(__attr __args[]) 468 { 469 __attr * const _data = &__args[1]; 470 __attr * const start = &__args[2]; 471 __attr * const size = &__args[3]; 472 /* _data interpreted as string */ 473 char *s = _data->strvalue, *sub; 474 /* start.__data__ interpreted as int */ 475 int i = __load_via_object(start->value, __pos___data__).intvalue; 476 /* size.__data__ interpreted as int */ 477 int l = __load_via_object(size->value, __pos___data__).intvalue; 478 479 /* Reserve space for a new string. */ 480 sub = (char *) __ALLOCATE(l + 1, sizeof(char)); 481 strncpy(sub, s + i, l); /* does not null terminate but final byte should be zero */ 482 return __new_str(sub); 483 } 484 485 /* List operations. */ 486 487 __attr __fn_native__list_init(__attr __args[]) 488 { 489 __attr * const size = &__args[1]; 490 /* size.__data__ interpreted as int */ 491 unsigned int n = __load_via_object(size->value, __pos___data__).intvalue; 492 __attr attr = {0, .seqvalue=__new_fragment(n)}; 493 494 /* Return the __data__ attribute. */ 495 return attr; 496 } 497 498 __attr __fn_native__list_setsize(__attr __args[]) 499 { 500 __attr * const _data = &__args[1]; 501 __attr * const size = &__args[2]; 502 /* _data interpreted as list */ 503 __fragment *data = _data->seqvalue; 504 /* size.__data__ interpreted as int */ 505 unsigned int n = __load_via_object(size->value, __pos___data__).intvalue; 506 507 data->size = n; 508 return __builtins___none_None; 509 } 510 511 __attr __fn_native__list_append(__attr __args[]) 512 { 513 __attr * const self = &__args[1]; 514 __attr * const value = &__args[2]; 515 /* self.__data__ interpreted as list */ 516 __fragment *data = __load_via_object(self->value, __pos___data__).seqvalue; 517 __fragment *newdata = __fragment_append(data, value); 518 519 /* Replace the __data__ attribute if appropriate. */ 520 if (newdata != data) 521 __store_via_object(self->value, __pos___data__, ((__attr) {0, .seqvalue=newdata})); 522 return __builtins___none_None; 523 } 524 525 __attr __fn_native__list_concat(__attr __args[]) 526 { 527 __attr * const self = &__args[1]; 528 __attr * const other = &__args[2]; 529 /* self.__data__, other interpreted as list */ 530 __fragment *data = __load_via_object(self->value, __pos___data__).seqvalue; 531 __fragment *other_data = other->seqvalue; 532 __fragment *newdata = data; 533 unsigned int size = data->size, capacity = data->capacity; 534 unsigned int other_size = other_data->size; 535 unsigned int i, j, n; 536 537 /* Re-allocate the fragment if the capacity has been reached. */ 538 if (size + other_size >= capacity) 539 { 540 n = size + other_size; 541 newdata = (__fragment *) __REALLOCATE(data, __FRAGMENT_SIZE(n)); 542 newdata->capacity = n; 543 } 544 545 /* Copy the elements from the other list and increment the list size. */ 546 for (i = size, j = 0; j < other_size; i++, j++) 547 newdata->attrs[i] = other_data->attrs[j]; 548 newdata->size = n; 549 550 /* Replace the __data__ attribute if appropriate. */ 551 if (newdata != data) 552 __store_via_object(self->value, __pos___data__, ((__attr) {0, .seqvalue=newdata})); 553 return __builtins___none_None; 554 } 555 556 __attr __fn_native__list_len(__attr __args[]) 557 { 558 __attr * const _data = &__args[1]; 559 /* _data interpreted as fragment */ 560 unsigned int size = _data->seqvalue->size; 561 562 /* Return the new integer. */ 563 return __new_int(size); 564 } 565 566 __attr __fn_native__list_nonempty(__attr __args[]) 567 { 568 __attr * const _data = &__args[1]; 569 570 return _data->seqvalue->size ? __builtins___boolean_True : __builtins___boolean_False; 571 } 572 573 __attr __fn_native__list_element(__attr __args[]) 574 { 575 __attr * const _data = &__args[1]; 576 __attr * const index = &__args[2]; 577 /* _data interpreted as fragment */ 578 __attr *elements = _data->seqvalue->attrs; 579 /* index.__data__ interpreted as int */ 580 int i = __load_via_object(index->value, __pos___data__).intvalue; 581 582 return elements[i]; 583 } 584 585 __attr __fn_native__list_setelement(__attr __args[]) 586 { 587 __attr * const _data = &__args[1]; 588 __attr * const index = &__args[2]; 589 __attr * const value = &__args[3]; 590 /* _data interpreted as fragment */ 591 __attr *elements = _data->seqvalue->attrs; 592 /* index.__data__ interpreted as int */ 593 int i = __load_via_object(index->value, __pos___data__).intvalue; 594 595 /* Set the element. */ 596 elements[i] = *value; 597 return __builtins___none_None; 598 } 599 600 /* Buffer operations. */ 601 602 __attr __fn_native__buffer_str(__attr __args[]) 603 { 604 __attr * const _data = &__args[1]; 605 /* _data interpreted as buffer */ 606 __fragment *data = _data->seqvalue; 607 unsigned int size = 0, i, j, n; 608 char *s, *o; 609 610 /* Calculate the size of the string. */ 611 for (i = 0; i < data->size; i++) 612 size += strlen(__load_via_object(data->attrs[i].value, __pos___data__).strvalue); 613 614 /* Reserve space for a new string. */ 615 s = (char *) __ALLOCATE(size + 1, sizeof(char)); 616 617 /* Build a single string from the buffer contents. */ 618 for (i = 0, j = 0; i < data->size; i++) 619 { 620 o = __load_via_object(data->attrs[i].value, __pos___data__).strvalue; 621 n = strlen(o); 622 strncpy(s + j, o, n); /* does not null terminate but final byte should be zero */ 623 j += n; 624 } 625 626 /* Return a new string. */ 627 return __new_str(s); 628 } 629 630 /* Method binding. */ 631 632 __attr __fn_native__get_using(__attr __args[]) 633 { 634 __attr * const callable = &__args[1]; 635 __attr * const instance = &__args[2]; 636 637 return __replace_context(instance->value, *callable); 638 } 639 640 /* Introspection. */ 641 642 __attr __fn_native__object_getattr(__attr __args[]) 643 { 644 __attr * const obj = &__args[1]; 645 __attr * const name = &__args[2]; 646 __attr * const _default = &__args[3]; 647 648 /* NOTE: To be written. */ 649 return __builtins___none_None; 650 } 651 652 static int __issubclass(__ref obj, __attr cls) 653 { 654 return (__HASATTR(obj, __TYPEPOS(cls.value), __TYPECODE(cls.value))); 655 } 656 657 __attr __fn_native__isinstance(__attr __args[]) 658 { 659 __attr * const obj = &__args[1]; 660 __attr * const cls = &__args[2]; 661 662 /* cls must be a class. */ 663 if (__is_instance(obj->value) && __issubclass(__get_class(obj->value), *cls)) 664 return __builtins___boolean_True; 665 else 666 return __builtins___boolean_False; 667 } 668 669 __attr __fn_native__issubclass(__attr __args[]) 670 { 671 __attr * const obj = &__args[1]; 672 __attr * const cls = &__args[2]; 673 674 /* obj and cls must be classes. */ 675 if (__issubclass(obj->value, *cls)) 676 return __builtins___boolean_True; 677 else 678 return __builtins___boolean_False; 679 } 680 681 /* Input/output. */ 682 683 __attr __fn_native__fopen(__attr __args[]) 684 { 685 __attr * const filename = &__args[1]; 686 __attr * const mode = &__args[2]; 687 /* filename.__data__ interpreted as string */ 688 char *fn = __load_via_object(filename->value, __pos___data__).strvalue; 689 /* mode.__data__ interpreted as string */ 690 char *s = __load_via_object(mode->value, __pos___data__).strvalue; 691 FILE *f; 692 __attr attr; 693 694 errno = 0; 695 f = fopen(fn, s); 696 697 /* Produce an exception if the operation failed. */ 698 699 if (f == NULL) 700 __raise_io_error(__new_int(errno)); 701 702 /* Return the __data__ attribute. */ 703 704 else 705 { 706 attr.context = 0; 707 attr.datavalue = (void *) f; 708 return attr; 709 } 710 } 711 712 __attr __fn_native__fdopen(__attr __args[]) 713 { 714 __attr * const fd = &__args[1]; 715 __attr * const mode = &__args[2]; 716 /* fd.__data__ interpreted as int */ 717 int i = __load_via_object(fd->value, __pos___data__).intvalue; 718 /* mode.__data__ interpreted as string */ 719 char *s = __load_via_object(mode->value, __pos___data__).strvalue; 720 FILE *f; 721 __attr attr; 722 723 errno = 0; 724 f = fdopen(i, s); 725 726 /* Produce an exception if the operation failed. */ 727 728 if (f == NULL) 729 __raise_io_error(__new_int(errno)); 730 731 /* Return the __data__ attribute. */ 732 733 else 734 { 735 attr.context = 0; 736 attr.datavalue = (void *) f; 737 return attr; 738 } 739 } 740 741 __attr __fn_native__fread(__attr __args[]) 742 { 743 __attr * const fp = &__args[1]; 744 __attr * const size = &__args[2]; 745 /* fp interpreted as FILE reference */ 746 FILE *f = (FILE *) fp->datavalue; 747 /* size.__data__ interpreted as int */ 748 int to_read = __load_via_object(size->value, __pos___data__).intvalue; 749 char buf[to_read]; 750 size_t have_read; 751 int error; 752 char *s; 753 754 have_read = fread(buf, sizeof(char), to_read, f); 755 756 if (have_read != to_read) 757 { 758 if (feof(f) && (have_read == 0)) 759 __raise_eof_error(); 760 else if (error = ferror(f)) 761 __raise_io_error(__new_int(error)); 762 } 763 764 /* Reserve space for a new string. */ 765 766 s = __ALLOCATE(have_read + 1, sizeof(char)); 767 strncpy(s, (char *) buf, have_read); /* does not null terminate but final byte should be zero */ 768 return __new_str(s); 769 } 770 771 __attr __fn_native__fwrite(__attr __args[]) 772 { 773 __attr * const fp = &__args[1]; 774 __attr * const str = &__args[2]; 775 /* fp interpreted as FILE reference */ 776 FILE *f = (FILE *) fp->datavalue; 777 /* str.__data__ interpreted as string */ 778 char *s = __load_via_object(str->value, __pos___data__).strvalue; 779 size_t to_write = strlen(s); 780 size_t have_written = fwrite(s, sizeof(char), to_write, f); 781 int error; 782 783 if (have_written != to_write) 784 { 785 if (feof(f)) 786 __raise_eof_error(); 787 else if (error = ferror(f)) 788 __raise_io_error(__new_int(error)); 789 } 790 791 return __builtins___none_None; 792 } 793 794 __attr __fn_native__read(__attr __args[]) 795 { 796 __attr * const fd = &__args[1]; 797 __attr * const n = &__args[2]; 798 /* fd.__data__ interpreted as int */ 799 int i = __load_via_object(fd->value, __pos___data__).intvalue; 800 /* n.__data__ interpreted as int */ 801 int to_read = __load_via_object(n->value, __pos___data__).intvalue; 802 char buf[to_read]; 803 ssize_t have_read; 804 char *s; 805 806 errno = 0; 807 have_read = read(i, buf, to_read * sizeof(char)); 808 809 if (have_read == -1) 810 __raise_io_error(__new_int(errno)); 811 else 812 { 813 /* Reserve space for a new string. */ 814 815 s = __ALLOCATE(have_read + 1, 1); 816 strncpy(s, (char *) buf, have_read); /* does not null terminate but final byte should be zero */ 817 return __new_str(s); 818 } 819 } 820 821 __attr __fn_native__write(__attr __args[]) 822 { 823 __attr * const fd = &__args[1]; 824 __attr * const str = &__args[2]; 825 /* fd.__data__ interpreted as int */ 826 int i = __load_via_object(fd->value, __pos___data__).intvalue; 827 /* str.__data__ interpreted as string */ 828 char *s = __load_via_object(str->value, __pos___data__).strvalue; 829 830 write(i, s, sizeof(char) * strlen(s)); 831 return __builtins___none_None; 832 } 833 834 /* Module initialisation. */ 835 836 void __main_native() 837 { 838 }