python-2.5.2/win32/Lib/platform.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     1 #!/usr/bin/env python
       
     2 
       
     3 """ This module tries to retrieve as much platform-identifying data as
       
     4     possible. It makes this information available via function APIs.
       
     5 
       
     6     If called from the command line, it prints the platform
       
     7     information concatenated as single string to stdout. The output
       
     8     format is useable as part of a filename.
       
     9 
       
    10 """
       
    11 #    This module is maintained by Marc-Andre Lemburg <mal@egenix.com>.
       
    12 #    If you find problems, please submit bug reports/patches via the
       
    13 #    Python SourceForge Project Page and assign them to "lemburg".
       
    14 #
       
    15 #    Note: Please keep this module compatible to Python 1.5.2.
       
    16 #
       
    17 #    Still needed:
       
    18 #    * more support for WinCE
       
    19 #    * support for MS-DOS (PythonDX ?)
       
    20 #    * support for Amiga and other still unsupported platforms running Python
       
    21 #    * support for additional Linux distributions
       
    22 #
       
    23 #    Many thanks to all those who helped adding platform-specific
       
    24 #    checks (in no particular order):
       
    25 #
       
    26 #      Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell,
       
    27 #      Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef
       
    28 #      Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
       
    29 #      Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
       
    30 #      Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
       
    31 #      Colin Kong, Trent Mick, Guido van Rossum
       
    32 #
       
    33 #    History:
       
    34 #
       
    35 #    <see CVS and SVN checkin messages for history>
       
    36 #
       
    37 #    1.0.3 - added normalization of Windows system name
       
    38 #    1.0.2 - added more Windows support
       
    39 #    1.0.1 - reformatted to make doc.py happy
       
    40 #    1.0.0 - reformatted a bit and checked into Python CVS
       
    41 #    0.8.0 - added sys.version parser and various new access
       
    42 #            APIs (python_version(), python_compiler(), etc.)
       
    43 #    0.7.2 - fixed architecture() to use sizeof(pointer) where available
       
    44 #    0.7.1 - added support for Caldera OpenLinux
       
    45 #    0.7.0 - some fixes for WinCE; untabified the source file
       
    46 #    0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
       
    47 #            vms_lib.getsyi() configured
       
    48 #    0.6.1 - added code to prevent 'uname -p' on platforms which are
       
    49 #            known not to support it
       
    50 #    0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
       
    51 #            did some cleanup of the interfaces - some APIs have changed
       
    52 #    0.5.5 - fixed another type in the MacOS code... should have
       
    53 #            used more coffee today ;-)
       
    54 #    0.5.4 - fixed a few typos in the MacOS code
       
    55 #    0.5.3 - added experimental MacOS support; added better popen()
       
    56 #            workarounds in _syscmd_ver() -- still not 100% elegant
       
    57 #            though
       
    58 #    0.5.2 - fixed uname() to return '' instead of 'unknown' in all
       
    59 #            return values (the system uname command tends to return
       
    60 #            'unknown' instead of just leaving the field emtpy)
       
    61 #    0.5.1 - included code for slackware dist; added exception handlers
       
    62 #            to cover up situations where platforms don't have os.popen
       
    63 #            (e.g. Mac) or fail on socket.gethostname(); fixed libc
       
    64 #            detection RE
       
    65 #    0.5.0 - changed the API names referring to system commands to *syscmd*;
       
    66 #            added java_ver(); made syscmd_ver() a private
       
    67 #            API (was system_ver() in previous versions) -- use uname()
       
    68 #            instead; extended the win32_ver() to also return processor
       
    69 #            type information
       
    70 #    0.4.0 - added win32_ver() and modified the platform() output for WinXX
       
    71 #    0.3.4 - fixed a bug in _follow_symlinks()
       
    72 #    0.3.3 - fixed popen() and "file" command invokation bugs
       
    73 #    0.3.2 - added architecture() API and support for it in platform()
       
    74 #    0.3.1 - fixed syscmd_ver() RE to support Windows NT
       
    75 #    0.3.0 - added system alias support
       
    76 #    0.2.3 - removed 'wince' again... oh well.
       
    77 #    0.2.2 - added 'wince' to syscmd_ver() supported platforms
       
    78 #    0.2.1 - added cache logic and changed the platform string format
       
    79 #    0.2.0 - changed the API to use functions instead of module globals
       
    80 #            since some action take too long to be run on module import
       
    81 #    0.1.0 - first release
       
    82 #
       
    83 #    You can always get the latest version of this module at:
       
    84 #
       
    85 #             http://www.egenix.com/files/python/platform.py
       
    86 #
       
    87 #    If that URL should fail, try contacting the author.
       
    88 
       
    89 __copyright__ = """
       
    90     Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
       
    91     Copyright (c) 2000-2003, eGenix.com Software GmbH; mailto:info@egenix.com
       
    92 
       
    93     Permission to use, copy, modify, and distribute this software and its
       
    94     documentation for any purpose and without fee or royalty is hereby granted,
       
    95     provided that the above copyright notice appear in all copies and that
       
    96     both that copyright notice and this permission notice appear in
       
    97     supporting documentation or portions thereof, including modifications,
       
    98     that you make.
       
    99 
       
   100     EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
       
   101     THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
       
   102     FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
       
   103     INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
       
   104     FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
       
   105     NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
       
   106     WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
       
   107 
       
   108 """
       
   109 
       
   110 __version__ = '1.0.4'
       
   111 
       
   112 import sys,string,os,re
       
   113 
       
   114 ### Platform specific APIs
       
   115 
       
   116 _libc_search = re.compile(r'(__libc_init)'
       
   117                           '|'
       
   118                           '(GLIBC_([0-9.]+))'
       
   119                           '|'
       
   120                           '(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)')
       
   121 
       
   122 def libc_ver(executable=sys.executable,lib='',version='',
       
   123 
       
   124              chunksize=2048):
       
   125 
       
   126     """ Tries to determine the libc version that the file executable
       
   127         (which defaults to the Python interpreter) is linked against.
       
   128 
       
   129         Returns a tuple of strings (lib,version) which default to the
       
   130         given parameters in case the lookup fails.
       
   131 
       
   132         Note that the function has intimate knowledge of how different
       
   133         libc versions add symbols to the executable and thus is probably
       
   134         only useable for executables compiled using gcc.
       
   135 
       
   136         The file is read and scanned in chunks of chunksize bytes.
       
   137 
       
   138     """
       
   139     f = open(executable,'rb')
       
   140     binary = f.read(chunksize)
       
   141     pos = 0
       
   142     while 1:
       
   143         m = _libc_search.search(binary,pos)
       
   144         if not m:
       
   145             binary = f.read(chunksize)
       
   146             if not binary:
       
   147                 break
       
   148             pos = 0
       
   149             continue
       
   150         libcinit,glibc,glibcversion,so,threads,soversion = m.groups()
       
   151         if libcinit and not lib:
       
   152             lib = 'libc'
       
   153         elif glibc:
       
   154             if lib != 'glibc':
       
   155                 lib = 'glibc'
       
   156                 version = glibcversion
       
   157             elif glibcversion > version:
       
   158                 version = glibcversion
       
   159         elif so:
       
   160             if lib != 'glibc':
       
   161                 lib = 'libc'
       
   162                 if soversion > version:
       
   163                     version = soversion
       
   164                 if threads and version[-len(threads):] != threads:
       
   165                     version = version + threads
       
   166         pos = m.end()
       
   167     f.close()
       
   168     return lib,version
       
   169 
       
   170 def _dist_try_harder(distname,version,id):
       
   171 
       
   172     """ Tries some special tricks to get the distribution
       
   173         information in case the default method fails.
       
   174 
       
   175         Currently supports older SuSE Linux, Caldera OpenLinux and
       
   176         Slackware Linux distributions.
       
   177 
       
   178     """
       
   179     if os.path.exists('/var/adm/inst-log/info'):
       
   180         # SuSE Linux stores distribution information in that file
       
   181         info = open('/var/adm/inst-log/info').readlines()
       
   182         distname = 'SuSE'
       
   183         for line in info:
       
   184             tv = string.split(line)
       
   185             if len(tv) == 2:
       
   186                 tag,value = tv
       
   187             else:
       
   188                 continue
       
   189             if tag == 'MIN_DIST_VERSION':
       
   190                 version = string.strip(value)
       
   191             elif tag == 'DIST_IDENT':
       
   192                 values = string.split(value,'-')
       
   193                 id = values[2]
       
   194         return distname,version,id
       
   195 
       
   196     if os.path.exists('/etc/.installed'):
       
   197         # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
       
   198         info = open('/etc/.installed').readlines()
       
   199         for line in info:
       
   200             pkg = string.split(line,'-')
       
   201             if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
       
   202                 # XXX does Caldera support non Intel platforms ? If yes,
       
   203                 #     where can we find the needed id ?
       
   204                 return 'OpenLinux',pkg[1],id
       
   205 
       
   206     if os.path.isdir('/usr/lib/setup'):
       
   207         # Check for slackware verson tag file (thanks to Greg Andruk)
       
   208         verfiles = os.listdir('/usr/lib/setup')
       
   209         for n in range(len(verfiles)-1, -1, -1):
       
   210             if verfiles[n][:14] != 'slack-version-':
       
   211                 del verfiles[n]
       
   212         if verfiles:
       
   213             verfiles.sort()
       
   214             distname = 'slackware'
       
   215             version = verfiles[-1][14:]
       
   216             return distname,version,id
       
   217 
       
   218     return distname,version,id
       
   219 
       
   220 _release_filename = re.compile(r'(\w+)[-_](release|version)')
       
   221 _release_version = re.compile(r'([\d.]+)[^(]*(?:\((.+)\))?')
       
   222 
       
   223 # Note:In supported_dists below we need 'fedora' before 'redhat' as in
       
   224 # Fedora redhat-release is a link to fedora-release.
       
   225 
       
   226 def dist(distname='',version='',id='',
       
   227 
       
   228          supported_dists=('SuSE', 'debian', 'fedora', 'redhat', 'mandrake')):
       
   229 
       
   230     """ Tries to determine the name of the Linux OS distribution name.
       
   231 
       
   232         The function first looks for a distribution release file in
       
   233         /etc and then reverts to _dist_try_harder() in case no
       
   234         suitable files are found.
       
   235 
       
   236         Returns a tuple (distname,version,id) which default to the
       
   237         args given as parameters.
       
   238 
       
   239     """
       
   240     try:
       
   241         etc = os.listdir('/etc')
       
   242     except os.error:
       
   243         # Probably not a Unix system
       
   244         return distname,version,id
       
   245     for file in etc:
       
   246         m = _release_filename.match(file)
       
   247         if m:
       
   248             _distname,dummy = m.groups()
       
   249             if _distname in supported_dists:
       
   250                 distname = _distname
       
   251                 break
       
   252     else:
       
   253         return _dist_try_harder(distname,version,id)
       
   254     f = open('/etc/'+file,'r')
       
   255     firstline = f.readline()
       
   256     f.close()
       
   257     m = _release_version.search(firstline)
       
   258     if m:
       
   259         _version,_id = m.groups()
       
   260         if _version:
       
   261             version = _version
       
   262         if _id:
       
   263             id = _id
       
   264     else:
       
   265         # Unkown format... take the first two words
       
   266         l = string.split(string.strip(firstline))
       
   267         if l:
       
   268             version = l[0]
       
   269             if len(l) > 1:
       
   270                 id = l[1]
       
   271     return distname,version,id
       
   272 
       
   273 class _popen:
       
   274 
       
   275     """ Fairly portable (alternative) popen implementation.
       
   276 
       
   277         This is mostly needed in case os.popen() is not available, or
       
   278         doesn't work as advertised, e.g. in Win9X GUI programs like
       
   279         PythonWin or IDLE.
       
   280 
       
   281         Writing to the pipe is currently not supported.
       
   282 
       
   283     """
       
   284     tmpfile = ''
       
   285     pipe = None
       
   286     bufsize = None
       
   287     mode = 'r'
       
   288 
       
   289     def __init__(self,cmd,mode='r',bufsize=None):
       
   290 
       
   291         if mode != 'r':
       
   292             raise ValueError,'popen()-emulation only supports read mode'
       
   293         import tempfile
       
   294         self.tmpfile = tmpfile = tempfile.mktemp()
       
   295         os.system(cmd + ' > %s' % tmpfile)
       
   296         self.pipe = open(tmpfile,'rb')
       
   297         self.bufsize = bufsize
       
   298         self.mode = mode
       
   299 
       
   300     def read(self):
       
   301 
       
   302         return self.pipe.read()
       
   303 
       
   304     def readlines(self):
       
   305 
       
   306         if self.bufsize is not None:
       
   307             return self.pipe.readlines()
       
   308 
       
   309     def close(self,
       
   310 
       
   311               remove=os.unlink,error=os.error):
       
   312 
       
   313         if self.pipe:
       
   314             rc = self.pipe.close()
       
   315         else:
       
   316             rc = 255
       
   317         if self.tmpfile:
       
   318             try:
       
   319                 remove(self.tmpfile)
       
   320             except error:
       
   321                 pass
       
   322         return rc
       
   323 
       
   324     # Alias
       
   325     __del__ = close
       
   326 
       
   327 def popen(cmd, mode='r', bufsize=None):
       
   328 
       
   329     """ Portable popen() interface.
       
   330     """
       
   331     # Find a working popen implementation preferring win32pipe.popen
       
   332     # over os.popen over _popen
       
   333     popen = None
       
   334     if os.environ.get('OS','') == 'Windows_NT':
       
   335         # On NT win32pipe should work; on Win9x it hangs due to bugs
       
   336         # in the MS C lib (see MS KnowledgeBase article Q150956)
       
   337         try:
       
   338             import win32pipe
       
   339         except ImportError:
       
   340             pass
       
   341         else:
       
   342             popen = win32pipe.popen
       
   343     if popen is None:
       
   344         if hasattr(os,'popen'):
       
   345             popen = os.popen
       
   346             # Check whether it works... it doesn't in GUI programs
       
   347             # on Windows platforms
       
   348             if sys.platform == 'win32': # XXX Others too ?
       
   349                 try:
       
   350                     popen('')
       
   351                 except os.error:
       
   352                     popen = _popen
       
   353         else:
       
   354             popen = _popen
       
   355     if bufsize is None:
       
   356         return popen(cmd,mode)
       
   357     else:
       
   358         return popen(cmd,mode,bufsize)
       
   359 
       
   360 def _norm_version(version,build=''):
       
   361 
       
   362     """ Normalize the version and build strings and return a single
       
   363         version string using the format major.minor.build (or patchlevel).
       
   364     """
       
   365     l = string.split(version,'.')
       
   366     if build:
       
   367         l.append(build)
       
   368     try:
       
   369         ints = map(int,l)
       
   370     except ValueError:
       
   371         strings = l
       
   372     else:
       
   373         strings = map(str,ints)
       
   374     version = string.join(strings[:3],'.')
       
   375     return version
       
   376 
       
   377 _ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
       
   378                          '.*'
       
   379                          'Version ([\d.]+))')
       
   380 
       
   381 def _syscmd_ver(system='',release='',version='',
       
   382 
       
   383                supported_platforms=('win32','win16','dos','os2')):
       
   384 
       
   385     """ Tries to figure out the OS version used and returns
       
   386         a tuple (system,release,version).
       
   387 
       
   388         It uses the "ver" shell command for this which is known
       
   389         to exists on Windows, DOS and OS/2. XXX Others too ?
       
   390 
       
   391         In case this fails, the given parameters are used as
       
   392         defaults.
       
   393 
       
   394     """
       
   395     if sys.platform not in supported_platforms:
       
   396         return system,release,version
       
   397 
       
   398     # Try some common cmd strings
       
   399     for cmd in ('ver','command /c ver','cmd /c ver'):
       
   400         try:
       
   401             pipe = popen(cmd)
       
   402             info = pipe.read()
       
   403             if pipe.close():
       
   404                 raise os.error,'command failed'
       
   405             # XXX How can I supress shell errors from being written
       
   406             #     to stderr ?
       
   407         except os.error,why:
       
   408             #print 'Command %s failed: %s' % (cmd,why)
       
   409             continue
       
   410         except IOError,why:
       
   411             #print 'Command %s failed: %s' % (cmd,why)
       
   412             continue
       
   413         else:
       
   414             break
       
   415     else:
       
   416         return system,release,version
       
   417 
       
   418     # Parse the output
       
   419     info = string.strip(info)
       
   420     m = _ver_output.match(info)
       
   421     if m:
       
   422         system,release,version = m.groups()
       
   423         # Strip trailing dots from version and release
       
   424         if release[-1] == '.':
       
   425             release = release[:-1]
       
   426         if version[-1] == '.':
       
   427             version = version[:-1]
       
   428         # Normalize the version and build strings (eliminating additional
       
   429         # zeros)
       
   430         version = _norm_version(version)
       
   431     return system,release,version
       
   432 
       
   433 def _win32_getvalue(key,name,default=''):
       
   434 
       
   435     """ Read a value for name from the registry key.
       
   436 
       
   437         In case this fails, default is returned.
       
   438 
       
   439     """
       
   440     from win32api import RegQueryValueEx
       
   441     try:
       
   442         return RegQueryValueEx(key,name)
       
   443     except:
       
   444         return default
       
   445 
       
   446 def win32_ver(release='',version='',csd='',ptype=''):
       
   447 
       
   448     """ Get additional version information from the Windows Registry
       
   449         and return a tuple (version,csd,ptype) referring to version
       
   450         number, CSD level and OS type (multi/single
       
   451         processor).
       
   452 
       
   453         As a hint: ptype returns 'Uniprocessor Free' on single
       
   454         processor NT machines and 'Multiprocessor Free' on multi
       
   455         processor machines. The 'Free' refers to the OS version being
       
   456         free of debugging code. It could also state 'Checked' which
       
   457         means the OS version uses debugging code, i.e. code that
       
   458         checks arguments, ranges, etc. (Thomas Heller).
       
   459 
       
   460         Note: this function only works if Mark Hammond's win32
       
   461         package is installed and obviously only runs on Win32
       
   462         compatible platforms.
       
   463 
       
   464     """
       
   465     # XXX Is there any way to find out the processor type on WinXX ?
       
   466     # XXX Is win32 available on Windows CE ?
       
   467     #
       
   468     # Adapted from code posted by Karl Putland to comp.lang.python.
       
   469     #
       
   470     # The mappings between reg. values and release names can be found
       
   471     # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
       
   472 
       
   473     # Import the needed APIs
       
   474     try:
       
   475         import win32api
       
   476     except ImportError:
       
   477         return release,version,csd,ptype
       
   478     from win32api import RegQueryValueEx,RegOpenKeyEx,RegCloseKey,GetVersionEx
       
   479     from win32con import HKEY_LOCAL_MACHINE,VER_PLATFORM_WIN32_NT,\
       
   480                          VER_PLATFORM_WIN32_WINDOWS
       
   481 
       
   482     # Find out the registry key and some general version infos
       
   483     maj,min,buildno,plat,csd = GetVersionEx()
       
   484     version = '%i.%i.%i' % (maj,min,buildno & 0xFFFF)
       
   485     if csd[:13] == 'Service Pack ':
       
   486         csd = 'SP' + csd[13:]
       
   487     if plat == VER_PLATFORM_WIN32_WINDOWS:
       
   488         regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
       
   489         # Try to guess the release name
       
   490         if maj == 4:
       
   491             if min == 0:
       
   492                 release = '95'
       
   493             elif min == 10:
       
   494                 release = '98'
       
   495             elif min == 90:
       
   496                 release = 'Me'
       
   497             else:
       
   498                 release = 'postMe'
       
   499         elif maj == 5:
       
   500             release = '2000'
       
   501     elif plat == VER_PLATFORM_WIN32_NT:
       
   502         regkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
       
   503         if maj <= 4:
       
   504             release = 'NT'
       
   505         elif maj == 5:
       
   506             if min == 0:
       
   507                 release = '2000'
       
   508             elif min == 1:
       
   509                 release = 'XP'
       
   510             elif min == 2:
       
   511                 release = '2003Server'
       
   512             else:
       
   513                 release = 'post2003'
       
   514     else:
       
   515         if not release:
       
   516             # E.g. Win3.1 with win32s
       
   517             release = '%i.%i' % (maj,min)
       
   518         return release,version,csd,ptype
       
   519 
       
   520     # Open the registry key
       
   521     try:
       
   522         keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE,regkey)
       
   523         # Get a value to make sure the key exists...
       
   524         RegQueryValueEx(keyCurVer,'SystemRoot')
       
   525     except:
       
   526         return release,version,csd,ptype
       
   527 
       
   528     # Parse values
       
   529     #subversion = _win32_getvalue(keyCurVer,
       
   530     #                            'SubVersionNumber',
       
   531     #                            ('',1))[0]
       
   532     #if subversion:
       
   533     #   release = release + subversion # 95a, 95b, etc.
       
   534     build = _win32_getvalue(keyCurVer,
       
   535                             'CurrentBuildNumber',
       
   536                             ('',1))[0]
       
   537     ptype = _win32_getvalue(keyCurVer,
       
   538                            'CurrentType',
       
   539                            (ptype,1))[0]
       
   540 
       
   541     # Normalize version
       
   542     version = _norm_version(version,build)
       
   543 
       
   544     # Close key
       
   545     RegCloseKey(keyCurVer)
       
   546     return release,version,csd,ptype
       
   547 
       
   548 def _mac_ver_lookup(selectors,default=None):
       
   549 
       
   550     from gestalt import gestalt
       
   551     import MacOS
       
   552     l = []
       
   553     append = l.append
       
   554     for selector in selectors:
       
   555         try:
       
   556             append(gestalt(selector))
       
   557         except (RuntimeError, MacOS.Error):
       
   558             append(default)
       
   559     return l
       
   560 
       
   561 def _bcd2str(bcd):
       
   562 
       
   563     return hex(bcd)[2:]
       
   564 
       
   565 def mac_ver(release='',versioninfo=('','',''),machine=''):
       
   566 
       
   567     """ Get MacOS version information and return it as tuple (release,
       
   568         versioninfo, machine) with versioninfo being a tuple (version,
       
   569         dev_stage, non_release_version).
       
   570 
       
   571         Entries which cannot be determined are set to the paramter values
       
   572         which default to ''. All tuple entries are strings.
       
   573 
       
   574         Thanks to Mark R. Levinson for mailing documentation links and
       
   575         code examples for this function. Documentation for the
       
   576         gestalt() API is available online at:
       
   577 
       
   578            http://www.rgaros.nl/gestalt/
       
   579 
       
   580     """
       
   581     # Check whether the version info module is available
       
   582     try:
       
   583         import gestalt
       
   584         import MacOS
       
   585     except ImportError:
       
   586         return release,versioninfo,machine
       
   587     # Get the infos
       
   588     sysv,sysu,sysa = _mac_ver_lookup(('sysv','sysu','sysa'))
       
   589     # Decode the infos
       
   590     if sysv:
       
   591         major = (sysv & 0xFF00) >> 8
       
   592         minor = (sysv & 0x00F0) >> 4
       
   593         patch = (sysv & 0x000F)
       
   594         release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
       
   595     if sysu:
       
   596         major =  int((sysu & 0xFF000000L) >> 24)
       
   597         minor =  (sysu & 0x00F00000) >> 20
       
   598         bugfix = (sysu & 0x000F0000) >> 16
       
   599         stage =  (sysu & 0x0000FF00) >> 8
       
   600         nonrel = (sysu & 0x000000FF)
       
   601         version = '%s.%i.%i' % (_bcd2str(major),minor,bugfix)
       
   602         nonrel = _bcd2str(nonrel)
       
   603         stage = {0x20:'development',
       
   604                  0x40:'alpha',
       
   605                  0x60:'beta',
       
   606                  0x80:'final'}.get(stage,'')
       
   607         versioninfo = (version,stage,nonrel)
       
   608     if sysa:
       
   609         machine = {0x1: '68k',
       
   610                    0x2: 'PowerPC',
       
   611                    0xa: 'i386'}.get(sysa,'')
       
   612     return release,versioninfo,machine
       
   613 
       
   614 def _java_getprop(name,default):
       
   615 
       
   616     from java.lang import System
       
   617     try:
       
   618         return System.getProperty(name)
       
   619     except:
       
   620         return default
       
   621 
       
   622 def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
       
   623 
       
   624     """ Version interface for Jython.
       
   625 
       
   626         Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
       
   627         a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
       
   628         tuple (os_name,os_version,os_arch).
       
   629 
       
   630         Values which cannot be determined are set to the defaults
       
   631         given as parameters (which all default to '').
       
   632 
       
   633     """
       
   634     # Import the needed APIs
       
   635     try:
       
   636         import java.lang
       
   637     except ImportError:
       
   638         return release,vendor,vminfo,osinfo
       
   639 
       
   640     vendor = _java_getprop('java.vendor',vendor)
       
   641     release = _java_getprop('java.version',release)
       
   642     vm_name,vm_release,vm_vendor = vminfo
       
   643     vm_name = _java_getprop('java.vm.name',vm_name)
       
   644     vm_vendor = _java_getprop('java.vm.vendor',vm_vendor)
       
   645     vm_release = _java_getprop('java.vm.version',vm_release)
       
   646     vminfo = vm_name,vm_release,vm_vendor
       
   647     os_name,os_version,os_arch = osinfo
       
   648     os_arch = _java_getprop('java.os.arch',os_arch)
       
   649     os_name = _java_getprop('java.os.name',os_name)
       
   650     os_version = _java_getprop('java.os.version',os_version)
       
   651     osinfo = os_name,os_version,os_arch
       
   652 
       
   653     return release,vendor,vminfo,osinfo
       
   654 
       
   655 ### System name aliasing
       
   656 
       
   657 def system_alias(system,release,version):
       
   658 
       
   659     """ Returns (system,release,version) aliased to common
       
   660         marketing names used for some systems.
       
   661 
       
   662         It also does some reordering of the information in some cases
       
   663         where it would otherwise cause confusion.
       
   664 
       
   665     """
       
   666     if system == 'Rhapsody':
       
   667         # Apple's BSD derivative
       
   668         # XXX How can we determine the marketing release number ?
       
   669         return 'MacOS X Server',system+release,version
       
   670 
       
   671     elif system == 'SunOS':
       
   672         # Sun's OS
       
   673         if release < '5':
       
   674             # These releases use the old name SunOS
       
   675             return system,release,version
       
   676         # Modify release (marketing release = SunOS release - 3)
       
   677         l = string.split(release,'.')
       
   678         if l:
       
   679             try:
       
   680                 major = int(l[0])
       
   681             except ValueError:
       
   682                 pass
       
   683             else:
       
   684                 major = major - 3
       
   685                 l[0] = str(major)
       
   686                 release = string.join(l,'.')
       
   687         if release < '6':
       
   688             system = 'Solaris'
       
   689         else:
       
   690             # XXX Whatever the new SunOS marketing name is...
       
   691             system = 'Solaris'
       
   692 
       
   693     elif system == 'IRIX64':
       
   694         # IRIX reports IRIX64 on platforms with 64-bit support; yet it
       
   695         # is really a version and not a different platform, since 32-bit
       
   696         # apps are also supported..
       
   697         system = 'IRIX'
       
   698         if version:
       
   699             version = version + ' (64bit)'
       
   700         else:
       
   701             version = '64bit'
       
   702 
       
   703     elif system in ('win32','win16'):
       
   704         # In case one of the other tricks
       
   705         system = 'Windows'
       
   706 
       
   707     return system,release,version
       
   708 
       
   709 ### Various internal helpers
       
   710 
       
   711 def _platform(*args):
       
   712 
       
   713     """ Helper to format the platform string in a filename
       
   714         compatible format e.g. "system-version-machine".
       
   715     """
       
   716     # Format the platform string
       
   717     platform = string.join(
       
   718         map(string.strip,
       
   719             filter(len,args)),
       
   720         '-')
       
   721 
       
   722     # Cleanup some possible filename obstacles...
       
   723     replace = string.replace
       
   724     platform = replace(platform,' ','_')
       
   725     platform = replace(platform,'/','-')
       
   726     platform = replace(platform,'\\','-')
       
   727     platform = replace(platform,':','-')
       
   728     platform = replace(platform,';','-')
       
   729     platform = replace(platform,'"','-')
       
   730     platform = replace(platform,'(','-')
       
   731     platform = replace(platform,')','-')
       
   732 
       
   733     # No need to report 'unknown' information...
       
   734     platform = replace(platform,'unknown','')
       
   735 
       
   736     # Fold '--'s and remove trailing '-'
       
   737     while 1:
       
   738         cleaned = replace(platform,'--','-')
       
   739         if cleaned == platform:
       
   740             break
       
   741         platform = cleaned
       
   742     while platform[-1] == '-':
       
   743         platform = platform[:-1]
       
   744 
       
   745     return platform
       
   746 
       
   747 def _node(default=''):
       
   748 
       
   749     """ Helper to determine the node name of this machine.
       
   750     """
       
   751     try:
       
   752         import socket
       
   753     except ImportError:
       
   754         # No sockets...
       
   755         return default
       
   756     try:
       
   757         return socket.gethostname()
       
   758     except socket.error:
       
   759         # Still not working...
       
   760         return default
       
   761 
       
   762 # os.path.abspath is new in Python 1.5.2:
       
   763 if not hasattr(os.path,'abspath'):
       
   764 
       
   765     def _abspath(path,
       
   766 
       
   767                  isabs=os.path.isabs,join=os.path.join,getcwd=os.getcwd,
       
   768                  normpath=os.path.normpath):
       
   769 
       
   770         if not isabs(path):
       
   771             path = join(getcwd(), path)
       
   772         return normpath(path)
       
   773 
       
   774 else:
       
   775 
       
   776     _abspath = os.path.abspath
       
   777 
       
   778 def _follow_symlinks(filepath):
       
   779 
       
   780     """ In case filepath is a symlink, follow it until a
       
   781         real file is reached.
       
   782     """
       
   783     filepath = _abspath(filepath)
       
   784     while os.path.islink(filepath):
       
   785         filepath = os.path.normpath(
       
   786             os.path.join(filepath,os.readlink(filepath)))
       
   787     return filepath
       
   788 
       
   789 def _syscmd_uname(option,default=''):
       
   790 
       
   791     """ Interface to the system's uname command.
       
   792     """
       
   793     if sys.platform in ('dos','win32','win16','os2'):
       
   794         # XXX Others too ?
       
   795         return default
       
   796     try:
       
   797         f = os.popen('uname %s 2> /dev/null' % option)
       
   798     except (AttributeError,os.error):
       
   799         return default
       
   800     output = string.strip(f.read())
       
   801     rc = f.close()
       
   802     if not output or rc:
       
   803         return default
       
   804     else:
       
   805         return output
       
   806 
       
   807 def _syscmd_file(target,default=''):
       
   808 
       
   809     """ Interface to the system's file command.
       
   810 
       
   811         The function uses the -b option of the file command to have it
       
   812         ommit the filename in its output and if possible the -L option
       
   813         to have the command follow symlinks. It returns default in
       
   814         case the command should fail.
       
   815 
       
   816     """
       
   817     target = _follow_symlinks(target)
       
   818     try:
       
   819         f = os.popen('file %s 2> /dev/null' % target)
       
   820     except (AttributeError,os.error):
       
   821         return default
       
   822     output = string.strip(f.read())
       
   823     rc = f.close()
       
   824     if not output or rc:
       
   825         return default
       
   826     else:
       
   827         return output
       
   828 
       
   829 ### Information about the used architecture
       
   830 
       
   831 # Default values for architecture; non-empty strings override the
       
   832 # defaults given as parameters
       
   833 _default_architecture = {
       
   834     'win32': ('','WindowsPE'),
       
   835     'win16': ('','Windows'),
       
   836     'dos': ('','MSDOS'),
       
   837 }
       
   838 
       
   839 _architecture_split = re.compile(r'[\s,]').split
       
   840 
       
   841 def architecture(executable=sys.executable,bits='',linkage=''):
       
   842 
       
   843     """ Queries the given executable (defaults to the Python interpreter
       
   844         binary) for various architecture information.
       
   845 
       
   846         Returns a tuple (bits,linkage) which contains information about
       
   847         the bit architecture and the linkage format used for the
       
   848         executable. Both values are returned as strings.
       
   849 
       
   850         Values that cannot be determined are returned as given by the
       
   851         parameter presets. If bits is given as '', the sizeof(pointer)
       
   852         (or sizeof(long) on Python version < 1.5.2) is used as
       
   853         indicator for the supported pointer size.
       
   854 
       
   855         The function relies on the system's "file" command to do the
       
   856         actual work. This is available on most if not all Unix
       
   857         platforms. On some non-Unix platforms where the "file" command
       
   858         does not exist and the executable is set to the Python interpreter
       
   859         binary defaults from _default_architecture are used.
       
   860 
       
   861     """
       
   862     # Use the sizeof(pointer) as default number of bits if nothing
       
   863     # else is given as default.
       
   864     if not bits:
       
   865         import struct
       
   866         try:
       
   867             size = struct.calcsize('P')
       
   868         except struct.error:
       
   869             # Older installations can only query longs
       
   870             size = struct.calcsize('l')
       
   871         bits = str(size*8) + 'bit'
       
   872 
       
   873     # Get data from the 'file' system command
       
   874     output = _syscmd_file(executable,'')
       
   875 
       
   876     if not output and \
       
   877        executable == sys.executable:
       
   878         # "file" command did not return anything; we'll try to provide
       
   879         # some sensible defaults then...
       
   880         if _default_architecture.has_key(sys.platform):
       
   881             b,l = _default_architecture[sys.platform]
       
   882             if b:
       
   883                 bits = b
       
   884             if l:
       
   885                 linkage = l
       
   886         return bits,linkage
       
   887 
       
   888     # Split the output into a list of strings omitting the filename
       
   889     fileout = _architecture_split(output)[1:]
       
   890 
       
   891     if 'executable' not in fileout:
       
   892         # Format not supported
       
   893         return bits,linkage
       
   894 
       
   895     # Bits
       
   896     if '32-bit' in fileout:
       
   897         bits = '32bit'
       
   898     elif 'N32' in fileout:
       
   899         # On Irix only
       
   900         bits = 'n32bit'
       
   901     elif '64-bit' in fileout:
       
   902         bits = '64bit'
       
   903 
       
   904     # Linkage
       
   905     if 'ELF' in fileout:
       
   906         linkage = 'ELF'
       
   907     elif 'PE' in fileout:
       
   908         # E.g. Windows uses this format
       
   909         if 'Windows' in fileout:
       
   910             linkage = 'WindowsPE'
       
   911         else:
       
   912             linkage = 'PE'
       
   913     elif 'COFF' in fileout:
       
   914         linkage = 'COFF'
       
   915     elif 'MS-DOS' in fileout:
       
   916         linkage = 'MSDOS'
       
   917     else:
       
   918         # XXX the A.OUT format also falls under this class...
       
   919         pass
       
   920 
       
   921     return bits,linkage
       
   922 
       
   923 ### Portable uname() interface
       
   924 
       
   925 _uname_cache = None
       
   926 
       
   927 def uname():
       
   928 
       
   929     """ Fairly portable uname interface. Returns a tuple
       
   930         of strings (system,node,release,version,machine,processor)
       
   931         identifying the underlying platform.
       
   932 
       
   933         Note that unlike the os.uname function this also returns
       
   934         possible processor information as an additional tuple entry.
       
   935 
       
   936         Entries which cannot be determined are set to ''.
       
   937 
       
   938     """
       
   939     global _uname_cache
       
   940 
       
   941     if _uname_cache is not None:
       
   942         return _uname_cache
       
   943 
       
   944     # Get some infos from the builtin os.uname API...
       
   945     try:
       
   946         system,node,release,version,machine = os.uname()
       
   947 
       
   948     except AttributeError:
       
   949         # Hmm, no uname... we'll have to poke around the system then.
       
   950         system = sys.platform
       
   951         release = ''
       
   952         version = ''
       
   953         node = _node()
       
   954         machine = ''
       
   955         processor = ''
       
   956         use_syscmd_ver = 1
       
   957 
       
   958         # Try win32_ver() on win32 platforms
       
   959         if system == 'win32':
       
   960             release,version,csd,ptype = win32_ver()
       
   961             if release and version:
       
   962                 use_syscmd_ver = 0
       
   963 
       
   964         # Try the 'ver' system command available on some
       
   965         # platforms
       
   966         if use_syscmd_ver:
       
   967             system,release,version = _syscmd_ver(system)
       
   968             # Normalize system to what win32_ver() normally returns
       
   969             # (_syscmd_ver() tends to return the vendor name as well)
       
   970             if system == 'Microsoft Windows':
       
   971                 system = 'Windows'
       
   972 
       
   973         # In case we still don't know anything useful, we'll try to
       
   974         # help ourselves
       
   975         if system in ('win32','win16'):
       
   976             if not version:
       
   977                 if system == 'win32':
       
   978                     version = '32bit'
       
   979                 else:
       
   980                     version = '16bit'
       
   981             system = 'Windows'
       
   982 
       
   983         elif system[:4] == 'java':
       
   984             release,vendor,vminfo,osinfo = java_ver()
       
   985             system = 'Java'
       
   986             version = string.join(vminfo,', ')
       
   987             if not version:
       
   988                 version = vendor
       
   989 
       
   990         elif os.name == 'mac':
       
   991             release,(version,stage,nonrel),machine = mac_ver()
       
   992             system = 'MacOS'
       
   993 
       
   994     else:
       
   995         # System specific extensions
       
   996         if system == 'OpenVMS':
       
   997             # OpenVMS seems to have release and version mixed up
       
   998             if not release or release == '0':
       
   999                 release = version
       
  1000                 version = ''
       
  1001             # Get processor information
       
  1002             try:
       
  1003                 import vms_lib
       
  1004             except ImportError:
       
  1005                 pass
       
  1006             else:
       
  1007                 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
       
  1008                 if (cpu_number >= 128):
       
  1009                     processor = 'Alpha'
       
  1010                 else:
       
  1011                     processor = 'VAX'
       
  1012         else:
       
  1013             # Get processor information from the uname system command
       
  1014             processor = _syscmd_uname('-p','')
       
  1015 
       
  1016     # 'unknown' is not really any useful as information; we'll convert
       
  1017     # it to '' which is more portable
       
  1018     if system == 'unknown':
       
  1019         system = ''
       
  1020     if node == 'unknown':
       
  1021         node = ''
       
  1022     if release == 'unknown':
       
  1023         release = ''
       
  1024     if version == 'unknown':
       
  1025         version = ''
       
  1026     if machine == 'unknown':
       
  1027         machine = ''
       
  1028     if processor == 'unknown':
       
  1029         processor = ''
       
  1030 
       
  1031     #  normalize name
       
  1032     if system == 'Microsoft' and release == 'Windows':
       
  1033         system = 'Windows'
       
  1034         release = 'Vista'
       
  1035 
       
  1036     _uname_cache = system,node,release,version,machine,processor
       
  1037     return _uname_cache
       
  1038 
       
  1039 ### Direct interfaces to some of the uname() return values
       
  1040 
       
  1041 def system():
       
  1042 
       
  1043     """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
       
  1044 
       
  1045         An empty string is returned if the value cannot be determined.
       
  1046 
       
  1047     """
       
  1048     return uname()[0]
       
  1049 
       
  1050 def node():
       
  1051 
       
  1052     """ Returns the computer's network name (which may not be fully
       
  1053         qualified)
       
  1054 
       
  1055         An empty string is returned if the value cannot be determined.
       
  1056 
       
  1057     """
       
  1058     return uname()[1]
       
  1059 
       
  1060 def release():
       
  1061 
       
  1062     """ Returns the system's release, e.g. '2.2.0' or 'NT'
       
  1063 
       
  1064         An empty string is returned if the value cannot be determined.
       
  1065 
       
  1066     """
       
  1067     return uname()[2]
       
  1068 
       
  1069 def version():
       
  1070 
       
  1071     """ Returns the system's release version, e.g. '#3 on degas'
       
  1072 
       
  1073         An empty string is returned if the value cannot be determined.
       
  1074 
       
  1075     """
       
  1076     return uname()[3]
       
  1077 
       
  1078 def machine():
       
  1079 
       
  1080     """ Returns the machine type, e.g. 'i386'
       
  1081 
       
  1082         An empty string is returned if the value cannot be determined.
       
  1083 
       
  1084     """
       
  1085     return uname()[4]
       
  1086 
       
  1087 def processor():
       
  1088 
       
  1089     """ Returns the (true) processor name, e.g. 'amdk6'
       
  1090 
       
  1091         An empty string is returned if the value cannot be
       
  1092         determined. Note that many platforms do not provide this
       
  1093         information or simply return the same value as for machine(),
       
  1094         e.g.  NetBSD does this.
       
  1095 
       
  1096     """
       
  1097     return uname()[5]
       
  1098 
       
  1099 ### Various APIs for extracting information from sys.version
       
  1100 
       
  1101 _sys_version_parser = re.compile(r'([\w.+]+)\s*'
       
  1102                                   '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
       
  1103                                   '\[([^\]]+)\]?')
       
  1104 _sys_version_cache = None
       
  1105 
       
  1106 def _sys_version():
       
  1107 
       
  1108     """ Returns a parsed version of Python's sys.version as tuple
       
  1109         (version, buildno, builddate, compiler) referring to the Python
       
  1110         version, build number, build date/time as string and the compiler
       
  1111         identification string.
       
  1112 
       
  1113         Note that unlike the Python sys.version, the returned value
       
  1114         for the Python version will always include the patchlevel (it
       
  1115         defaults to '.0').
       
  1116 
       
  1117     """
       
  1118     global _sys_version_cache
       
  1119 
       
  1120     if _sys_version_cache is not None:
       
  1121         return _sys_version_cache
       
  1122     version, buildno, builddate, buildtime, compiler = \
       
  1123              _sys_version_parser.match(sys.version).groups()
       
  1124     builddate = builddate + ' ' + buildtime
       
  1125     l = string.split(version, '.')
       
  1126     if len(l) == 2:
       
  1127         l.append('0')
       
  1128         version = string.join(l, '.')
       
  1129     _sys_version_cache = (version, buildno, builddate, compiler)
       
  1130     return _sys_version_cache
       
  1131 
       
  1132 def python_version():
       
  1133 
       
  1134     """ Returns the Python version as string 'major.minor.patchlevel'
       
  1135 
       
  1136         Note that unlike the Python sys.version, the returned value
       
  1137         will always include the patchlevel (it defaults to 0).
       
  1138 
       
  1139     """
       
  1140     return _sys_version()[0]
       
  1141 
       
  1142 def python_version_tuple():
       
  1143 
       
  1144     """ Returns the Python version as tuple (major, minor, patchlevel)
       
  1145         of strings.
       
  1146 
       
  1147         Note that unlike the Python sys.version, the returned value
       
  1148         will always include the patchlevel (it defaults to 0).
       
  1149 
       
  1150     """
       
  1151     return string.split(_sys_version()[0], '.')
       
  1152 
       
  1153 def python_build():
       
  1154 
       
  1155     """ Returns a tuple (buildno, builddate) stating the Python
       
  1156         build number and date as strings.
       
  1157 
       
  1158     """
       
  1159     return _sys_version()[1:3]
       
  1160 
       
  1161 def python_compiler():
       
  1162 
       
  1163     """ Returns a string identifying the compiler used for compiling
       
  1164         Python.
       
  1165 
       
  1166     """
       
  1167     return _sys_version()[3]
       
  1168 
       
  1169 ### The Opus Magnum of platform strings :-)
       
  1170 
       
  1171 _platform_cache = {}
       
  1172 
       
  1173 def platform(aliased=0, terse=0):
       
  1174 
       
  1175     """ Returns a single string identifying the underlying platform
       
  1176         with as much useful information as possible (but no more :).
       
  1177 
       
  1178         The output is intended to be human readable rather than
       
  1179         machine parseable. It may look different on different
       
  1180         platforms and this is intended.
       
  1181 
       
  1182         If "aliased" is true, the function will use aliases for
       
  1183         various platforms that report system names which differ from
       
  1184         their common names, e.g. SunOS will be reported as
       
  1185         Solaris. The system_alias() function is used to implement
       
  1186         this.
       
  1187 
       
  1188         Setting terse to true causes the function to return only the
       
  1189         absolute minimum information needed to identify the platform.
       
  1190 
       
  1191     """
       
  1192     result = _platform_cache.get((aliased, terse), None)
       
  1193     if result is not None:
       
  1194         return result
       
  1195 
       
  1196     # Get uname information and then apply platform specific cosmetics
       
  1197     # to it...
       
  1198     system,node,release,version,machine,processor = uname()
       
  1199     if machine == processor:
       
  1200         processor = ''
       
  1201     if aliased:
       
  1202         system,release,version = system_alias(system,release,version)
       
  1203 
       
  1204     if system == 'Windows':
       
  1205         # MS platforms
       
  1206         rel,vers,csd,ptype = win32_ver(version)
       
  1207         if terse:
       
  1208             platform = _platform(system,release)
       
  1209         else:
       
  1210             platform = _platform(system,release,version,csd)
       
  1211 
       
  1212     elif system in ('Linux',):
       
  1213         # Linux based systems
       
  1214         distname,distversion,distid = dist('')
       
  1215         if distname and not terse:
       
  1216             platform = _platform(system,release,machine,processor,
       
  1217                                  'with',
       
  1218                                  distname,distversion,distid)
       
  1219         else:
       
  1220             # If the distribution name is unknown check for libc vs. glibc
       
  1221             libcname,libcversion = libc_ver(sys.executable)
       
  1222             platform = _platform(system,release,machine,processor,
       
  1223                                  'with',
       
  1224                                  libcname+libcversion)
       
  1225     elif system == 'Java':
       
  1226         # Java platforms
       
  1227         r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
       
  1228         if terse:
       
  1229             platform = _platform(system,release,version)
       
  1230         else:
       
  1231             platform = _platform(system,release,version,
       
  1232                                  'on',
       
  1233                                  os_name,os_version,os_arch)
       
  1234 
       
  1235     elif system == 'MacOS':
       
  1236         # MacOS platforms
       
  1237         if terse:
       
  1238             platform = _platform(system,release)
       
  1239         else:
       
  1240             platform = _platform(system,release,machine)
       
  1241 
       
  1242     else:
       
  1243         # Generic handler
       
  1244         if terse:
       
  1245             platform = _platform(system,release)
       
  1246         else:
       
  1247             bits,linkage = architecture(sys.executable)
       
  1248             platform = _platform(system,release,machine,processor,bits,linkage)
       
  1249 
       
  1250     _platform_cache[(aliased, terse)] = platform
       
  1251     return platform
       
  1252 
       
  1253 ### Command line interface
       
  1254 
       
  1255 if __name__ == '__main__':
       
  1256     # Default is to print the aliased verbose platform string
       
  1257     terse = ('terse' in sys.argv or '--terse' in sys.argv)
       
  1258     aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
       
  1259     print platform(aliased,terse)
       
  1260     sys.exit(0)