PageRenderTime 27ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/rpython/module/ll_os_environ.py

https://github.com/thepian/pypy
Python | 198 lines | 158 code | 22 blank | 18 comment | 6 complexity | 80fcc99d0e0c41b706db5da0238d813d MD5 | raw file
  1. import os, sys
  2. from pypy.annotation import model as annmodel
  3. from pypy.rpython.controllerentry import Controller
  4. from pypy.rpython.extfunc import register_external
  5. from pypy.rpython.lltypesystem import rffi, lltype
  6. from pypy.rlib import rposix
  7. # ____________________________________________________________
  8. #
  9. # Annotation support to control access to 'os.environ' in the RPython program
  10. class OsEnvironController(Controller):
  11. knowntype = os.environ.__class__
  12. def convert(self, obj):
  13. return None # 'None' is good enough, there is only one os.environ
  14. def getitem(self, obj, key):
  15. # in the RPython program reads of 'os.environ[key]' are redirected here
  16. result = r_getenv(key)
  17. if result is None:
  18. raise KeyError
  19. return result
  20. def setitem(self, obj, key, value):
  21. # in the RPython program, 'os.environ[key] = value' is redirected here
  22. r_putenv(key, value)
  23. def delitem(self, obj, key):
  24. # in the RPython program, 'del os.environ[key]' is redirected here
  25. if r_getenv(key) is None:
  26. raise KeyError
  27. r_unsetenv(key)
  28. def get_keys(self, obj):
  29. # 'os.environ.keys' is redirected here - note that it's the getattr
  30. # that arrives here, not the actual method call!
  31. return r_envkeys
  32. def get_items(self, obj):
  33. # 'os.environ.items' is redirected here (not the actual method call!)
  34. return r_envitems
  35. def get_get(self, obj):
  36. # 'os.environ.get' is redirected here (not the actual method call!)
  37. return r_getenv
  38. # ____________________________________________________________
  39. #
  40. # Lower-level interface: dummy placeholders and external registations
  41. def r_getenv(name):
  42. just_a_placeholder # should return None if name not found
  43. os_getenv = rffi.llexternal('getenv', [rffi.CCHARP], rffi.CCHARP)
  44. def getenv_llimpl(name):
  45. l_name = rffi.str2charp(name)
  46. l_result = os_getenv(l_name)
  47. if l_result:
  48. result = rffi.charp2str(l_result)
  49. else:
  50. result = None
  51. rffi.free_charp(l_name)
  52. return result
  53. register_external(r_getenv, [str], annmodel.SomeString(can_be_None=True),
  54. export_name='ll_os.ll_os_getenv',
  55. llimpl=getenv_llimpl)
  56. # ____________________________________________________________
  57. def r_putenv(name, value):
  58. just_a_placeholder
  59. class EnvKeepalive:
  60. pass
  61. envkeepalive = EnvKeepalive()
  62. envkeepalive.byname = {}
  63. os_putenv = rffi.llexternal('putenv', [rffi.CCHARP], rffi.INT)
  64. def putenv_llimpl(name, value):
  65. l_string = rffi.str2charp('%s=%s' % (name, value))
  66. error = rffi.cast(lltype.Signed, os_putenv(l_string))
  67. if error:
  68. rffi.free_charp(l_string)
  69. raise OSError(rposix.get_errno(), "os_putenv failed")
  70. # keep 'l_string' alive - we know that the C library needs it
  71. # until the next call to putenv() with the same 'name'.
  72. l_oldstring = envkeepalive.byname.get(name, lltype.nullptr(rffi.CCHARP.TO))
  73. envkeepalive.byname[name] = l_string
  74. if l_oldstring:
  75. rffi.free_charp(l_oldstring)
  76. register_external(r_putenv, [str, str], annmodel.s_None,
  77. export_name='ll_os.ll_os_putenv',
  78. llimpl=putenv_llimpl)
  79. # ____________________________________________________________
  80. def r_unsetenv(name):
  81. # default implementation for platforms without a real unsetenv()
  82. r_putenv(name, '')
  83. if hasattr(__import__(os.name), 'unsetenv'):
  84. if sys.platform.startswith('darwin'):
  85. RETTYPE = lltype.Void
  86. os_unsetenv = rffi.llexternal('unsetenv', [rffi.CCHARP], RETTYPE)
  87. else:
  88. RETTYPE = rffi.INT
  89. _os_unsetenv = rffi.llexternal('unsetenv', [rffi.CCHARP], RETTYPE)
  90. def os_unsetenv(l_name):
  91. return rffi.cast(lltype.Signed, _os_unsetenv(l_name))
  92. def unsetenv_llimpl(name):
  93. l_name = rffi.str2charp(name)
  94. error = os_unsetenv(l_name) # 'error' is None on OS/X
  95. rffi.free_charp(l_name)
  96. if error:
  97. raise OSError(rposix.get_errno(), "os_unsetenv failed")
  98. try:
  99. l_oldstring = envkeepalive.byname[name]
  100. except KeyError:
  101. pass
  102. else:
  103. del envkeepalive.byname[name]
  104. rffi.free_charp(l_oldstring)
  105. register_external(r_unsetenv, [str], annmodel.s_None,
  106. export_name='ll_os.ll_os_unsetenv',
  107. llimpl=unsetenv_llimpl)
  108. # ____________________________________________________________
  109. # Access to the 'environ' external variable
  110. from pypy.translator.tool.cbuild import ExternalCompilationInfo
  111. if sys.platform.startswith('darwin'):
  112. CCHARPPP = rffi.CArrayPtr(rffi.CCHARPP)
  113. _os_NSGetEnviron = rffi.llexternal(
  114. '_NSGetEnviron', [], CCHARPPP,
  115. compilation_info=ExternalCompilationInfo(includes=['crt_externs.h'])
  116. )
  117. def os_get_environ():
  118. return _os_NSGetEnviron()[0]
  119. elif sys.platform.startswith('win'):
  120. os_get_environ, _os_set_environ = rffi.CExternVariable(
  121. rffi.CCHARPP,
  122. '_environ',
  123. ExternalCompilationInfo(includes=['stdlib.h']))
  124. else:
  125. os_get_environ, _os_set_environ = rffi.CExternVariable(rffi.CCHARPP,
  126. 'environ',
  127. ExternalCompilationInfo())
  128. # ____________________________________________________________
  129. def r_envkeys():
  130. just_a_placeholder
  131. def envkeys_llimpl():
  132. environ = os_get_environ()
  133. result = []
  134. i = 0
  135. while environ[i]:
  136. name_value = rffi.charp2str(environ[i])
  137. p = name_value.find('=')
  138. if p >= 0:
  139. result.append(name_value[:p])
  140. i += 1
  141. return result
  142. register_external(r_envkeys, [], [str], # returns a list of strings
  143. export_name='ll_os.ll_os_envkeys',
  144. llimpl=envkeys_llimpl)
  145. # ____________________________________________________________
  146. def r_envitems():
  147. just_a_placeholder
  148. def envitems_llimpl():
  149. environ = os_get_environ()
  150. result = []
  151. i = 0
  152. while environ[i]:
  153. name_value = rffi.charp2str(environ[i])
  154. p = name_value.find('=')
  155. if p >= 0:
  156. result.append((name_value[:p], name_value[p+1:]))
  157. i += 1
  158. return result
  159. register_external(r_envitems, [], [(str, str)],
  160. export_name='ll_os.ll_os_envitems',
  161. llimpl=envitems_llimpl)