|
93 | 93 | import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
|
94 | 94 | import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
|
95 | 95 | import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
|
| 96 | +import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; |
96 | 97 | import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
|
97 | 98 | import com.oracle.graal.python.nodes.util.CastToIndexNode;
|
| 99 | +import com.oracle.graal.python.nodes.util.CastToIntegerFromIntNode; |
98 | 100 | import com.oracle.graal.python.runtime.PosixResources;
|
99 | 101 | import com.oracle.graal.python.runtime.PythonContext;
|
100 | 102 | import com.oracle.graal.python.runtime.PythonCore;
|
| 103 | +import com.oracle.graal.python.runtime.PythonOptions; |
101 | 104 | import com.oracle.graal.python.runtime.exception.PException;
|
102 | 105 | import com.oracle.graal.python.runtime.exception.PythonErrorType;
|
103 | 106 | import com.oracle.graal.python.runtime.exception.PythonExitException;
|
@@ -1625,4 +1628,98 @@ int getAndSetUmask(int umask) {
|
1625 | 1628 | }
|
1626 | 1629 | }
|
1627 | 1630 | }
|
| 1631 | + |
| 1632 | + @Builtin(name = "get_terminal_size", maxNumOfPositionalArgs = 1) |
| 1633 | + @GenerateNodeFactory |
| 1634 | + abstract static class GetTerminalSizeNode extends PythonUnaryBuiltinNode { |
| 1635 | + private final static String ERROR_MESSAGE = "[Errno 9] Bad file descriptor"; |
| 1636 | + |
| 1637 | + @Child private CastToIntegerFromIntNode castIntNode; |
| 1638 | + @Child private GetTerminalSizeNode recursiveNode; |
| 1639 | + |
| 1640 | + @CompilationFinal private ConditionProfile errorProfile; |
| 1641 | + @CompilationFinal private ConditionProfile overflowProfile; |
| 1642 | + |
| 1643 | + private CastToIntegerFromIntNode getCastIntNode() { |
| 1644 | + if (castIntNode == null) { |
| 1645 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 1646 | + castIntNode = insert(CastToIntegerFromIntNode.create(val -> { |
| 1647 | + throw raise(PythonBuiltinClassType.TypeError, "an integer is required (got type %p)", val); |
| 1648 | + })); |
| 1649 | + } |
| 1650 | + return castIntNode; |
| 1651 | + } |
| 1652 | + |
| 1653 | + private ConditionProfile getErrorProfile() { |
| 1654 | + if (errorProfile == null) { |
| 1655 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 1656 | + errorProfile = ConditionProfile.createBinaryProfile(); |
| 1657 | + } |
| 1658 | + return errorProfile; |
| 1659 | + } |
| 1660 | + |
| 1661 | + private ConditionProfile getOverflowProfile() { |
| 1662 | + if (overflowProfile == null) { |
| 1663 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 1664 | + overflowProfile = ConditionProfile.createBinaryProfile(); |
| 1665 | + } |
| 1666 | + return overflowProfile; |
| 1667 | + } |
| 1668 | + |
| 1669 | + @Specialization(guards = "isNone(fd)") |
| 1670 | + PTuple getTerminalSize(@SuppressWarnings("unused") PNone fd) { |
| 1671 | + if (getErrorProfile().profile(getContext().getResources().getFileChannel(0) == null)) { |
| 1672 | + throw raise(OSError, ERROR_MESSAGE); |
| 1673 | + } |
| 1674 | + return factory().createTuple(new Object[]{PythonOptions.getTerminalWidth(), PythonOptions.getTerminalHeight()}); |
| 1675 | + } |
| 1676 | + |
| 1677 | + @Specialization |
| 1678 | + PTuple getTerminalSize(int fd) { |
| 1679 | + if (getErrorProfile().profile(getContext().getResources().getFileChannel(fd) == null)) { |
| 1680 | + throw raise(OSError, ERROR_MESSAGE); |
| 1681 | + } |
| 1682 | + return factory().createTuple(new Object[]{PythonOptions.getTerminalWidth(), PythonOptions.getTerminalHeight()}); |
| 1683 | + } |
| 1684 | + |
| 1685 | + @Specialization |
| 1686 | + PTuple getTerminalSize(long fd) { |
| 1687 | + if (getOverflowProfile().profile(Integer.MIN_VALUE > fd || fd > Integer.MAX_VALUE)) { |
| 1688 | + raise(PythonErrorType.OverflowError, "Python int too large to convert to C long"); |
| 1689 | + } |
| 1690 | + if (getErrorProfile().profile(getContext().getResources().getFileChannel((int) fd) == null)) { |
| 1691 | + throw raise(OSError, "[Errno 9] Bad file descriptor"); |
| 1692 | + } |
| 1693 | + return factory().createTuple(new Object[]{PythonOptions.getTerminalWidth(), PythonOptions.getTerminalHeight()}); |
| 1694 | + } |
| 1695 | + |
| 1696 | + @Specialization |
| 1697 | + @TruffleBoundary |
| 1698 | + PTuple getTerminalSize(PInt fd) { |
| 1699 | + int value; |
| 1700 | + try { |
| 1701 | + value = fd.intValueExact(); |
| 1702 | + if (getContext().getResources().getFileChannel(value) == null) { |
| 1703 | + throw raise(OSError, ERROR_MESSAGE); |
| 1704 | + } |
| 1705 | + } catch (ArithmeticException e) { |
| 1706 | + throw raise(PythonErrorType.OverflowError, "Python int too large to convert to C long"); |
| 1707 | + } |
| 1708 | + return factory().createTuple(new Object[]{PythonOptions.getTerminalWidth(), PythonOptions.getTerminalHeight()}); |
| 1709 | + } |
| 1710 | + |
| 1711 | + @Fallback |
| 1712 | + Object getTerminalSize(Object fd) { |
| 1713 | + Object value = getCastIntNode().execute(fd); |
| 1714 | + if (recursiveNode == null) { |
| 1715 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 1716 | + recursiveNode = create(); |
| 1717 | + } |
| 1718 | + return recursiveNode.execute(value); |
| 1719 | + } |
| 1720 | + |
| 1721 | + protected GetTerminalSizeNode create() { |
| 1722 | + return PosixModuleBuiltinsFactory.GetTerminalSizeNodeFactory.create(); |
| 1723 | + } |
| 1724 | + } |
1628 | 1725 | }
|
0 commit comments