PageRenderTime 40ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/pypy/module/_minimal_curses/fficurses.py

https://bitbucket.org/pypy/pypy/
Python | 143 lines | 115 code | 21 blank | 7 comment | 23 complexity | 338185173b02159ff614868833c8aa95 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. """ The ffi for rpython, need to be imported for side effects
  2. """
  3. from rpython.rtyper.lltypesystem import rffi
  4. from rpython.rtyper.lltypesystem import lltype
  5. from rpython.rtyper.tool import rffi_platform
  6. from rpython.rtyper.extfunc import register_external
  7. from pypy.module._minimal_curses import interp_curses
  8. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  9. # We cannot trust ncurses5-config, it's broken in various ways in
  10. # various versions. For example it might not list -ltinfo even though
  11. # it's needed, or --cflags might be completely empty. On Ubuntu 10.04
  12. # it gives -I/usr/include/ncurses, which doesn't exist at all. Crap.
  13. def try_cflags():
  14. yield ExternalCompilationInfo(includes=['curses.h', 'term.h'])
  15. yield ExternalCompilationInfo(includes=['curses.h', 'term.h'],
  16. include_dirs=['/usr/include/ncurses'])
  17. yield ExternalCompilationInfo(includes=['ncurses/curses.h',
  18. 'ncurses/term.h'])
  19. def try_ldflags():
  20. yield ExternalCompilationInfo(libraries=['curses'])
  21. yield ExternalCompilationInfo(libraries=['curses', 'tinfo'])
  22. yield ExternalCompilationInfo(libraries=['ncurses'])
  23. yield ExternalCompilationInfo(libraries=['ncurses'],
  24. library_dirs=['/usr/lib64'])
  25. def try_tools():
  26. try:
  27. yield ExternalCompilationInfo.from_pkg_config("ncurses")
  28. except Exception:
  29. pass
  30. try:
  31. yield ExternalCompilationInfo.from_config_tool("ncurses5-config")
  32. except Exception:
  33. pass
  34. def try_eci():
  35. for eci in try_tools():
  36. yield eci.merge(ExternalCompilationInfo(includes=['curses.h',
  37. 'term.h']))
  38. for eci1 in try_cflags():
  39. for eci2 in try_ldflags():
  40. yield eci1.merge(eci2)
  41. def guess_eci():
  42. for eci in try_eci():
  43. class CConfig:
  44. _compilation_info_ = eci
  45. HAS = rffi_platform.Has("setupterm")
  46. if rffi_platform.configure(CConfig)['HAS']:
  47. return eci
  48. raise ImportError("failed to guess where ncurses is installed. "
  49. "You might need to install libncurses5-dev or similar.")
  50. eci = guess_eci()
  51. INT = rffi.INT
  52. INTP = lltype.Ptr(lltype.Array(INT, hints={'nolength':True}))
  53. c_setupterm = rffi.llexternal('setupterm', [rffi.CCHARP, INT, INTP], INT,
  54. compilation_info=eci)
  55. c_tigetstr = rffi.llexternal('tigetstr', [rffi.CCHARP], rffi.CCHARP,
  56. compilation_info=eci)
  57. c_tparm = rffi.llexternal('tparm', [rffi.CCHARP, INT, INT, INT, INT, INT,
  58. INT, INT, INT, INT], rffi.CCHARP,
  59. compilation_info=eci)
  60. ERR = rffi.CConstant('ERR', lltype.Signed)
  61. OK = rffi.CConstant('OK', lltype.Signed)
  62. def curses_setupterm(term, fd):
  63. intp = lltype.malloc(INTP.TO, 1, flavor='raw')
  64. err = rffi.cast(lltype.Signed, c_setupterm(term, fd, intp))
  65. try:
  66. if err == ERR:
  67. errret = rffi.cast(lltype.Signed, intp[0])
  68. if errret == 0:
  69. msg = "setupterm: could not find terminal"
  70. elif errret == -1:
  71. msg = "setupterm: could not find terminfo database"
  72. else:
  73. msg = "setupterm: unknown error"
  74. raise interp_curses.curses_error(msg)
  75. interp_curses.module_info.setupterm_called = True
  76. finally:
  77. lltype.free(intp, flavor='raw')
  78. def curses_setupterm_null_llimpl(fd):
  79. curses_setupterm(lltype.nullptr(rffi.CCHARP.TO), fd)
  80. def curses_setupterm_llimpl(term, fd):
  81. ll_s = rffi.str2charp(term)
  82. try:
  83. curses_setupterm(ll_s, fd)
  84. finally:
  85. rffi.free_charp(ll_s)
  86. register_external(interp_curses._curses_setupterm_null,
  87. [int], llimpl=curses_setupterm_null_llimpl,
  88. export_name='_curses.setupterm_null')
  89. register_external(interp_curses._curses_setupterm,
  90. [str, int], llimpl=curses_setupterm_llimpl,
  91. export_name='_curses.setupterm')
  92. def check_setup_invoked():
  93. if not interp_curses.module_info.setupterm_called:
  94. raise interp_curses.curses_error("must call (at least) setupterm() first")
  95. def tigetstr_llimpl(cap):
  96. check_setup_invoked()
  97. ll_cap = rffi.str2charp(cap)
  98. try:
  99. ll_res = c_tigetstr(ll_cap)
  100. num = lltype.cast_ptr_to_int(ll_res)
  101. if num == 0 or num == -1:
  102. raise interp_curses.TermError()
  103. res = rffi.charp2str(ll_res)
  104. return res
  105. finally:
  106. rffi.free_charp(ll_cap)
  107. register_external(interp_curses._curses_tigetstr, [str], str,
  108. export_name='_curses.tigetstr', llimpl=tigetstr_llimpl)
  109. def tparm_llimpl(s, args):
  110. check_setup_invoked()
  111. l = [0, 0, 0, 0, 0, 0, 0, 0, 0]
  112. for i in range(min(len(args), 9)):
  113. l[i] = args[i]
  114. ll_s = rffi.str2charp(s)
  115. # XXX nasty trick stolen from CPython
  116. ll_res = c_tparm(ll_s, l[0], l[1], l[2], l[3], l[4], l[5], l[6],
  117. l[7], l[8])
  118. rffi.free_charp(ll_s)
  119. res = rffi.charp2str(ll_res)
  120. return res
  121. register_external(interp_curses._curses_tparm, [str, [int]], str,
  122. export_name='_curses.tparm', llimpl=tparm_llimpl)