Mercurial > cpython-lru_cache-weakref
comparison Python/fileutils.c @ 65163:7879a8ec7f79
Ooops, fileutils.c contains twice the same code
I suppose that I reapplied my local patch creating Python/fileutils.c whereas
the file already existed.
| author | Victor Stinner <victor.stinner@haypocalc.com> |
|---|---|
| date | Thu, 07 Oct 2010 21:55:44 +0000 |
| parents | 39014f0abc32 |
| children | 1f3919af8a53 |
comparison
equal
deleted
inserted
replaced
| 65162:39014f0abc32 | 65163:7879a8ec7f79 |
|---|---|
| 374 return buf; | 374 return buf; |
| 375 #endif | 375 #endif |
| 376 } | 376 } |
| 377 | 377 |
| 378 #endif | 378 #endif |
| 379 | |
| 380 #include "Python.h" | |
| 381 | |
| 382 #ifdef HAVE_STAT | |
| 383 | |
| 384 /* Decode a byte string from the locale encoding with the | |
| 385 surrogateescape error handler (undecodable bytes are decoded as characters | |
| 386 in range U+DC80..U+DCFF). If a byte sequence can be decoded as a surrogate | |
| 387 character, escape the bytes using the surrogateescape error handler instead | |
| 388 of decoding them. | |
| 389 | |
| 390 Use _Py_wchar2char() to encode the character string back to a byte string. | |
| 391 | |
| 392 Return a pointer to a newly allocated (wide) character string (use | |
| 393 PyMem_Free() to free the memory), or NULL on error (conversion error or | |
| 394 memory error). */ | |
| 395 wchar_t* | |
| 396 _Py_char2wchar(char* arg) | |
| 397 { | |
| 398 wchar_t *res; | |
| 399 #ifdef HAVE_BROKEN_MBSTOWCS | |
| 400 /* Some platforms have a broken implementation of | |
| 401 * mbstowcs which does not count the characters that | |
| 402 * would result from conversion. Use an upper bound. | |
| 403 */ | |
| 404 size_t argsize = strlen(arg); | |
| 405 #else | |
| 406 size_t argsize = mbstowcs(NULL, arg, 0); | |
| 407 #endif | |
| 408 size_t count; | |
| 409 unsigned char *in; | |
| 410 wchar_t *out; | |
| 411 #ifdef HAVE_MBRTOWC | |
| 412 mbstate_t mbs; | |
| 413 #endif | |
| 414 if (argsize != (size_t)-1) { | |
| 415 res = (wchar_t *)PyMem_Malloc((argsize+1)*sizeof(wchar_t)); | |
| 416 if (!res) | |
| 417 goto oom; | |
| 418 count = mbstowcs(res, arg, argsize+1); | |
| 419 if (count != (size_t)-1) { | |
| 420 wchar_t *tmp; | |
| 421 /* Only use the result if it contains no | |
| 422 surrogate characters. */ | |
| 423 for (tmp = res; *tmp != 0 && | |
| 424 (*tmp < 0xd800 || *tmp > 0xdfff); tmp++) | |
| 425 ; | |
| 426 if (*tmp == 0) | |
| 427 return res; | |
| 428 } | |
| 429 PyMem_Free(res); | |
| 430 } | |
| 431 /* Conversion failed. Fall back to escaping with surrogateescape. */ | |
| 432 #ifdef HAVE_MBRTOWC | |
| 433 /* Try conversion with mbrtwoc (C99), and escape non-decodable bytes. */ | |
| 434 | |
| 435 /* Overallocate; as multi-byte characters are in the argument, the | |
| 436 actual output could use less memory. */ | |
| 437 argsize = strlen(arg) + 1; | |
| 438 res = (wchar_t*)PyMem_Malloc(argsize*sizeof(wchar_t)); | |
| 439 if (!res) goto oom; | |
| 440 in = (unsigned char*)arg; | |
| 441 out = res; | |
| 442 memset(&mbs, 0, sizeof mbs); | |
| 443 while (argsize) { | |
| 444 size_t converted = mbrtowc(out, (char*)in, argsize, &mbs); | |
| 445 if (converted == 0) | |
| 446 /* Reached end of string; null char stored. */ | |
| 447 break; | |
| 448 if (converted == (size_t)-2) { | |
| 449 /* Incomplete character. This should never happen, | |
| 450 since we provide everything that we have - | |
| 451 unless there is a bug in the C library, or I | |
| 452 misunderstood how mbrtowc works. */ | |
| 453 fprintf(stderr, "unexpected mbrtowc result -2\n"); | |
| 454 return NULL; | |
| 455 } | |
| 456 if (converted == (size_t)-1) { | |
| 457 /* Conversion error. Escape as UTF-8b, and start over | |
| 458 in the initial shift state. */ | |
| 459 *out++ = 0xdc00 + *in++; | |
| 460 argsize--; | |
| 461 memset(&mbs, 0, sizeof mbs); | |
| 462 continue; | |
| 463 } | |
| 464 if (*out >= 0xd800 && *out <= 0xdfff) { | |
| 465 /* Surrogate character. Escape the original | |
| 466 byte sequence with surrogateescape. */ | |
| 467 argsize -= converted; | |
| 468 while (converted--) | |
| 469 *out++ = 0xdc00 + *in++; | |
| 470 continue; | |
| 471 } | |
| 472 /* successfully converted some bytes */ | |
| 473 in += converted; | |
| 474 argsize -= converted; | |
| 475 out++; | |
| 476 } | |
| 477 #else | |
| 478 /* Cannot use C locale for escaping; manually escape as if charset | |
| 479 is ASCII (i.e. escape all bytes > 128. This will still roundtrip | |
| 480 correctly in the locale's charset, which must be an ASCII superset. */ | |
| 481 res = PyMem_Malloc((strlen(arg)+1)*sizeof(wchar_t)); | |
| 482 if (!res) goto oom; | |
| 483 in = (unsigned char*)arg; | |
| 484 out = res; | |
| 485 while(*in) | |
| 486 if(*in < 128) | |
| 487 *out++ = *in++; | |
| 488 else | |
| 489 *out++ = 0xdc00 + *in++; | |
| 490 *out = 0; | |
| 491 #endif | |
| 492 return res; | |
| 493 oom: | |
| 494 fprintf(stderr, "out of memory\n"); | |
| 495 return NULL; | |
| 496 } | |
| 497 | |
| 498 /* Encode a (wide) character string to the locale encoding with the | |
| 499 surrogateescape error handler (characters in range U+DC80..U+DCFF are | |
| 500 converted to bytes 0x80..0xFF). | |
| 501 | |
| 502 This function is the reverse of _Py_char2wchar(). | |
| 503 | |
| 504 Return a pointer to a newly allocated byte string (use PyMem_Free() to free | |
| 505 the memory), or NULL on error (conversion error or memory error). */ | |
| 506 char* | |
| 507 _Py_wchar2char(const wchar_t *text) | |
| 508 { | |
| 509 const size_t len = wcslen(text); | |
| 510 char *result = NULL, *bytes = NULL; | |
| 511 size_t i, size, converted; | |
| 512 wchar_t c, buf[2]; | |
| 513 | |
| 514 /* The function works in two steps: | |
| 515 1. compute the length of the output buffer in bytes (size) | |
| 516 2. outputs the bytes */ | |
| 517 size = 0; | |
| 518 buf[1] = 0; | |
| 519 while (1) { | |
| 520 for (i=0; i < len; i++) { | |
| 521 c = text[i]; | |
| 522 if (c >= 0xdc80 && c <= 0xdcff) { | |
| 523 /* UTF-8b surrogate */ | |
| 524 if (bytes != NULL) { | |
| 525 *bytes++ = c - 0xdc00; | |
| 526 size--; | |
| 527 } | |
| 528 else | |
| 529 size++; | |
| 530 continue; | |
| 531 } | |
| 532 else { | |
| 533 buf[0] = c; | |
| 534 if (bytes != NULL) | |
| 535 converted = wcstombs(bytes, buf, size); | |
| 536 else | |
| 537 converted = wcstombs(NULL, buf, 0); | |
| 538 if (converted == (size_t)-1) { | |
| 539 if (result != NULL) | |
| 540 PyMem_Free(result); | |
| 541 return NULL; | |
| 542 } | |
| 543 if (bytes != NULL) { | |
| 544 bytes += converted; | |
| 545 size -= converted; | |
| 546 } | |
| 547 else | |
| 548 size += converted; | |
| 549 } | |
| 550 } | |
| 551 if (result != NULL) { | |
| 552 *bytes = 0; | |
| 553 break; | |
| 554 } | |
| 555 | |
| 556 size += 1; /* nul byte at the end */ | |
| 557 result = PyMem_Malloc(size); | |
| 558 if (result == NULL) | |
| 559 return NULL; | |
| 560 bytes = result; | |
| 561 } | |
| 562 return result; | |
| 563 } | |
| 564 | |
| 565 #if defined(MS_WINDOWS) || defined(HAVE_STAT) | |
| 566 int | |
| 567 _Py_wstat(const wchar_t* path, struct stat *buf) | |
| 568 { | |
| 569 /* In principle, this should use HAVE__WSTAT, and _wstat | |
| 570 should be detected by autoconf. However, no current | |
| 571 POSIX system provides that function, so testing for | |
| 572 it is pointless. | |
| 573 Not sure whether the MS_WINDOWS guards are necessary: | |
| 574 perhaps for cygwin/mingw builds? | |
| 575 */ | |
| 576 #ifdef MS_WINDOWS | |
| 577 return _wstat(path, buf); | |
| 578 #else | |
| 579 int err; | |
| 580 char *fname; | |
| 581 fname = _Py_wchar2char(path); | |
| 582 if (fname == NULL) { | |
| 583 errno = EINVAL; | |
| 584 return -1; | |
| 585 } | |
| 586 err = stat(fname, buf); | |
| 587 PyMem_Free(fname); | |
| 588 return err; | |
| 589 #endif | |
| 590 } | |
| 591 #endif | |
| 592 | |
| 593 /* Call _wstat() on Windows, or stat() otherwise. Only fill st_mode | |
| 594 attribute on Windows. Return 0 on success, -1 on stat error or (if | |
| 595 PyErr_Occurred()) unicode error. */ | |
| 596 | |
| 597 int | |
| 598 _Py_stat(PyObject *unicode, struct stat *statbuf) | |
| 599 { | |
| 600 #ifdef MS_WINDOWS | |
| 601 wchar_t *path; | |
| 602 int err; | |
| 603 struct _stat wstatbuf; | |
| 604 | |
| 605 path = PyUnicode_AsWideCharString(unicode, NULL); | |
| 606 if (path == NULL) | |
| 607 return -1; | |
| 608 err = _wstat(path, &wstatbuf); | |
| 609 PyMem_Free(path); | |
| 610 if (!err) | |
| 611 statbuf->st_mode = wstatbuf.st_mode; | |
| 612 return err; | |
| 613 #else | |
| 614 int ret; | |
| 615 PyObject *bytes = PyUnicode_EncodeFSDefault(unicode); | |
| 616 if (bytes == NULL) | |
| 617 return -1; | |
| 618 ret = stat(PyBytes_AS_STRING(bytes), statbuf); | |
| 619 Py_DECREF(bytes); | |
| 620 return ret; | |
| 621 #endif | |
| 622 } | |
| 623 | |
| 624 FILE * | |
| 625 _Py_wfopen(const wchar_t *path, const wchar_t *mode) | |
| 626 { | |
| 627 #ifndef MS_WINDOWS | |
| 628 FILE *f; | |
| 629 char *cpath; | |
| 630 char cmode[10]; | |
| 631 size_t r; | |
| 632 r = wcstombs(cmode, mode, 10); | |
| 633 if (r == (size_t)-1 || r >= 10) { | |
| 634 errno = EINVAL; | |
| 635 return NULL; | |
| 636 } | |
| 637 cpath = _Py_wchar2char(path); | |
| 638 if (cpath == NULL) | |
| 639 return NULL; | |
| 640 f = fopen(cpath, cmode); | |
| 641 PyMem_Free(cpath); | |
| 642 return f; | |
| 643 #else | |
| 644 return _wfopen(path, mode); | |
| 645 #endif | |
| 646 } | |
| 647 | |
| 648 /* Call _wfopen() on Windows, or fopen() otherwise. Return the new file | |
| 649 object on success, or NULL if the file cannot be open or (if | |
| 650 PyErr_Occurred()) on unicode error */ | |
| 651 | |
| 652 FILE* | |
| 653 _Py_fopen(PyObject *unicode, const char *mode) | |
| 654 { | |
| 655 #ifdef MS_WINDOWS | |
| 656 wchar_t *path; | |
| 657 wchar_t wmode[10]; | |
| 658 int usize; | |
| 659 FILE *f; | |
| 660 | |
| 661 usize = MultiByteToWideChar(CP_ACP, 0, mode, -1, wmode, sizeof(wmode)); | |
| 662 if (usize == 0) | |
| 663 return NULL; | |
| 664 | |
| 665 path = PyUnicode_AsWideCharString(unicode, NULL); | |
| 666 if (path == NULL) | |
| 667 return NULL; | |
| 668 f = _wfopen(path, wmode); | |
| 669 PyMem_Free(path); | |
| 670 return f; | |
| 671 #else | |
| 672 FILE *f; | |
| 673 PyObject *bytes = PyUnicode_EncodeFSDefault(unicode); | |
| 674 if (bytes == NULL) | |
| 675 return NULL; | |
| 676 f = fopen(PyBytes_AS_STRING(bytes), mode); | |
| 677 Py_DECREF(bytes); | |
| 678 return f; | |
| 679 #endif | |
| 680 } | |
| 681 | |
| 682 #ifdef HAVE_READLINK | |
| 683 int | |
| 684 _Py_wreadlink(const wchar_t *path, wchar_t *buf, size_t bufsiz) | |
| 685 { | |
| 686 char *cpath; | |
| 687 char cbuf[PATH_MAX]; | |
| 688 int res; | |
| 689 size_t r1; | |
| 690 | |
| 691 cpath = _Py_wchar2char(path); | |
| 692 if (cpath == NULL) { | |
| 693 errno = EINVAL; | |
| 694 return -1; | |
| 695 } | |
| 696 res = (int)readlink(cpath, cbuf, PATH_MAX); | |
| 697 PyMem_Free(cpath); | |
| 698 if (res == -1) | |
| 699 return -1; | |
| 700 if (res == PATH_MAX) { | |
| 701 errno = EINVAL; | |
| 702 return -1; | |
| 703 } | |
| 704 cbuf[res] = '\0'; /* buf will be null terminated */ | |
| 705 r1 = mbstowcs(buf, cbuf, bufsiz); | |
| 706 if (r1 == -1) { | |
| 707 errno = EINVAL; | |
| 708 return -1; | |
| 709 } | |
| 710 return (int)r1; | |
| 711 } | |
| 712 #endif | |
| 713 | |
| 714 #ifdef HAVE_REALPATH | |
| 715 wchar_t* | |
| 716 _Py_wrealpath(const wchar_t *path, wchar_t *resolved_path) | |
| 717 { | |
| 718 char *cpath; | |
| 719 char cresolved_path[PATH_MAX]; | |
| 720 char *res; | |
| 721 size_t r; | |
| 722 cpath = _Py_wchar2char(path); | |
| 723 if (cpath == NULL) { | |
| 724 errno = EINVAL; | |
| 725 return NULL; | |
| 726 } | |
| 727 res = realpath(cpath, cresolved_path); | |
| 728 PyMem_Free(cpath); | |
| 729 if (res == NULL) | |
| 730 return NULL; | |
| 731 r = mbstowcs(resolved_path, cresolved_path, PATH_MAX); | |
| 732 if (r == (size_t)-1 || r >= PATH_MAX) { | |
| 733 errno = EINVAL; | |
| 734 return NULL; | |
| 735 } | |
| 736 return resolved_path; | |
| 737 } | |
| 738 #endif | |
| 739 | |
| 740 wchar_t* | |
| 741 _Py_wgetcwd(wchar_t *buf, size_t size) | |
| 742 { | |
| 743 #ifdef MS_WINDOWS | |
| 744 return _wgetcwd(buf, size); | |
| 745 #else | |
| 746 char fname[PATH_MAX]; | |
| 747 if (getcwd(fname, PATH_MAX) == NULL) | |
| 748 return NULL; | |
| 749 if (mbstowcs(buf, fname, size) >= size) { | |
| 750 errno = ERANGE; | |
| 751 return NULL; | |
| 752 } | |
| 753 return buf; | |
| 754 #endif | |
| 755 } | |
| 756 | |
| 757 #endif | |
| 758 |
