/pypy/rpython/module/ll_os_environ.py
Python | 201 lines | 160 code | 23 blank | 18 comment | 6 complexity | de3415cb1e2cedef2e57a5343ab70b14 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
- import os, sys
- from pypy.annotation import model as annmodel
- from pypy.rpython.controllerentry import Controller
- from pypy.rpython.extfunc import register_external
- from pypy.rpython.lltypesystem import rffi, lltype
- from pypy.rpython.module import ll_os
- from pypy.rlib import rposix
- str0 = ll_os.str0
- # ____________________________________________________________
- #
- # Annotation support to control access to 'os.environ' in the RPython program
- class OsEnvironController(Controller):
- knowntype = os.environ.__class__
- def convert(self, obj):
- return None # 'None' is good enough, there is only one os.environ
- def getitem(self, obj, key):
- # in the RPython program reads of 'os.environ[key]' are redirected here
- result = r_getenv(key)
- if result is None:
- raise KeyError
- return result
- def setitem(self, obj, key, value):
- # in the RPython program, 'os.environ[key] = value' is redirected here
- r_putenv(key, value)
- def delitem(self, obj, key):
- # in the RPython program, 'del os.environ[key]' is redirected here
- if r_getenv(key) is None:
- raise KeyError
- r_unsetenv(key)
- def get_keys(self, obj):
- # 'os.environ.keys' is redirected here - note that it's the getattr
- # that arrives here, not the actual method call!
- return r_envkeys
- def get_items(self, obj):
- # 'os.environ.items' is redirected here (not the actual method call!)
- return r_envitems
- def get_get(self, obj):
- # 'os.environ.get' is redirected here (not the actual method call!)
- return r_getenv
- # ____________________________________________________________
- #
- # Lower-level interface: dummy placeholders and external registations
- def r_getenv(name):
- just_a_placeholder # should return None if name not found
- os_getenv = rffi.llexternal('getenv', [rffi.CCHARP], rffi.CCHARP)
- def getenv_llimpl(name):
- l_name = rffi.str2charp(name)
- l_result = os_getenv(l_name)
- if l_result:
- result = rffi.charp2str(l_result)
- else:
- result = None
- rffi.free_charp(l_name)
- return result
- register_external(r_getenv, [str0], annmodel.SomeString(can_be_None=True),
- export_name='ll_os.ll_os_getenv',
- llimpl=getenv_llimpl)
- # ____________________________________________________________
- def r_putenv(name, value):
- just_a_placeholder
- class EnvKeepalive:
- pass
- envkeepalive = EnvKeepalive()
- envkeepalive.byname = {}
- os_putenv = rffi.llexternal('putenv', [rffi.CCHARP], rffi.INT)
- def putenv_llimpl(name, value):
- l_string = rffi.str2charp('%s=%s' % (name, value))
- error = rffi.cast(lltype.Signed, os_putenv(l_string))
- if error:
- rffi.free_charp(l_string)
- raise OSError(rposix.get_errno(), "os_putenv failed")
- # keep 'l_string' alive - we know that the C library needs it
- # until the next call to putenv() with the same 'name'.
- l_oldstring = envkeepalive.byname.get(name, lltype.nullptr(rffi.CCHARP.TO))
- envkeepalive.byname[name] = l_string
- if l_oldstring:
- rffi.free_charp(l_oldstring)
- register_external(r_putenv, [str0, str0], annmodel.s_None,
- export_name='ll_os.ll_os_putenv',
- llimpl=putenv_llimpl)
- # ____________________________________________________________
- def r_unsetenv(name):
- # default implementation for platforms without a real unsetenv()
- r_putenv(name, '')
- if hasattr(__import__(os.name), 'unsetenv'):
- if sys.platform.startswith('darwin'):
- RETTYPE = lltype.Void
- os_unsetenv = rffi.llexternal('unsetenv', [rffi.CCHARP], RETTYPE)
- else:
- RETTYPE = rffi.INT
- _os_unsetenv = rffi.llexternal('unsetenv', [rffi.CCHARP], RETTYPE)
- def os_unsetenv(l_name):
- return rffi.cast(lltype.Signed, _os_unsetenv(l_name))
- def unsetenv_llimpl(name):
- l_name = rffi.str2charp(name)
- error = os_unsetenv(l_name) # 'error' is None on OS/X
- rffi.free_charp(l_name)
- if error:
- raise OSError(rposix.get_errno(), "os_unsetenv failed")
- try:
- l_oldstring = envkeepalive.byname[name]
- except KeyError:
- pass
- else:
- del envkeepalive.byname[name]
- rffi.free_charp(l_oldstring)
- register_external(r_unsetenv, [str0], annmodel.s_None,
- export_name='ll_os.ll_os_unsetenv',
- llimpl=unsetenv_llimpl)
- # ____________________________________________________________
- # Access to the 'environ' external variable
- from pypy.translator.tool.cbuild import ExternalCompilationInfo
- if sys.platform.startswith('darwin'):
- CCHARPPP = rffi.CArrayPtr(rffi.CCHARPP)
- _os_NSGetEnviron = rffi.llexternal(
- '_NSGetEnviron', [], CCHARPPP,
- compilation_info=ExternalCompilationInfo(includes=['crt_externs.h'])
- )
- def os_get_environ():
- return _os_NSGetEnviron()[0]
- elif sys.platform.startswith('win'):
- os_get_environ, _os_set_environ = rffi.CExternVariable(
- rffi.CCHARPP,
- '_environ',
- ExternalCompilationInfo(includes=['stdlib.h']))
- else:
- os_get_environ, _os_set_environ = rffi.CExternVariable(rffi.CCHARPP,
- 'environ',
- ExternalCompilationInfo())
- # ____________________________________________________________
- def r_envkeys():
- just_a_placeholder
- def envkeys_llimpl():
- environ = os_get_environ()
- result = []
- i = 0
- while environ[i]:
- name_value = rffi.charp2str(environ[i])
- p = name_value.find('=')
- if p >= 0:
- result.append(name_value[:p])
- i += 1
- return result
- register_external(r_envkeys, [], [str0], # returns a list of strings
- export_name='ll_os.ll_os_envkeys',
- llimpl=envkeys_llimpl)
- # ____________________________________________________________
- def r_envitems():
- just_a_placeholder
- def envitems_llimpl():
- environ = os_get_environ()
- result = []
- i = 0
- while environ[i]:
- name_value = rffi.charp2str(environ[i])
- p = name_value.find('=')
- if p >= 0:
- result.append((name_value[:p], name_value[p+1:]))
- i += 1
- return result
- register_external(r_envitems, [], [(str0, str0)],
- export_name='ll_os.ll_os_envitems',
- llimpl=envitems_llimpl)