########################################
# The contents of this file are subject to the MLX PUBLIC LICENSE version
# 1.0 (the "License"); you may not use this file except in
# compliance with the License.
# 
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
# the License for the specific language governing rights and limitations
# under the License.
# 
# The Original Source Code is "compClust", released 2003 September 03.
# 
# The Original Source Code was developed by the California Institute of
# Technology (Caltech).  Portions created by Caltech are Copyright (C)
# 2002-2003 California Institute of Technology. All Rights Reserved.
########################################
#
#        Author: Diane Trout
# Last Modified: $Date: 2003/09/05 01:27:40 $
#

"""
Utilities functions to read information from the /proc filesystem under Linux
"""

import os
import re
import string

tab_name_value_re = re.compile(":\t* *")
name_value_re = re.compile(": *")

def __readFile(filename):
  """list_of_lines_of_text = readFile(filename)

  given a filename read it into memory and return it as a list.
  """
  stream = open(filename)
  data   = stream.readlines()
  stream.close()
  return data

def __convertNameValueToDictionary(list):
  """dictionary = convertNameValueToDictionary( list_of_name_value_pairs )

  Given a list of name value pairs, construct a dictionary of them.
  """
  dictionary = {}
  for name, value in list:
    name = string.strip(name)
    value = string.strip(value)
    dictionary[name] = value
  return dictionary

def getProcessStatus(pid=None):
  """dictionary = getProcessStatus(pid)

  return the contents of /proc/pid/status as a dictionary. If a pid
  is not provided, the currently running processes pid is used instead.

  NOTE: This only works under linux.
  """
  if pid is None:
    pid = os.getpid()
  status_data = __readFile("/proc/%s/status" % (pid))

  name_value_pairs = map(tab_name_value_re.split, status_data)

  status = __convertNameValueToDictionary(name_value_pairs)

  # Remove the "kB" from fields containing it.
  kB_re = re.compile(" kB")
  for k, v in status.items():
    if kB_re.search(v):
      status[k] = int(kB_re.sub("", v))
  return status

def getCpuInfo():
  """Array of dictionaries = getCpuInfo()

  Return an array of dictionaries containing the cpu information
  for all the processors installed on the system.
  """
  
  cpuinfo_text = map(string.strip, __readFile("/proc/cpuinfo"))
  
  processors = []
  processor_list = []

  for cpuinfo_line in cpuinfo_text:
    # the cpu blocks are seperated by an empty line
    if len(cpuinfo_line) > 0:
      # if we have more data for this block append it
      processor_list.append(tab_name_value_re.split(cpuinfo_line))
    else:
      # we've finished a block so convert it to a dictionary
      # and reset our buffer
      processors.append(__convertNameValueToDictionary(processor_list))
      processor_list = []
      
  return processors

def getMemInfo():
  meminfo_text = map(string.strop, __readFile("/proc/meminfo"))
  # parse first 3 lines which don't have a simple name_value format
  
# test code
if __name__ == "__main__":
  import pprint
  pprint.pprint(getProcessStatus())
  print getCpuInfo()    
