Properties.py

説明を見る。
00001 #!/usr/bin/env python
00002 # -*- coding: euc-jp -*-
00003   
00004 
00005 ##
00006 # @file Properties.py
00007 # @brief Property list class (derived from Java Properties)
00008 # @date $Date: $
00009 # @author Noriaki Ando <n-ando@aist.go.jp> and Shinji Kurihara
00010 #
00011 # Copyright (C) 2006-2008
00012 #     Task-intelligence Research Group,
00013 #     Intelligent Systems Research Institute,
00014 #     National Institute of
00015 #         Advanced Industrial Science and Technology (AIST), Japan
00016 #     All rights reserved.
00017 
00018 
00019 import sys
00020 import string
00021 
00022 import OpenRTM
00023 
00024 
00025 ##
00026 # @if jp
00027 #
00028 # @class Properties
00029 # @brief プロパティセットを表現するクラス
00030 #
00031 # Properties クラスは、不変のプロパティセットを表す。 Properties をストリーム
00032 # に保管したり、ストリームからロードしたりすることができる。
00033 # プロパティリストの各キー、およびそれに対応する値は文字列となっている。
00034 #
00035 # プロパティリストには、その「デフォルト値」として別のプロパティリストを持つ
00036 # ことができる。元のプロパティリストでプロパティキーが見つからないと、この
00037 # 2番目のプロパティリストが検索される。 
00038 #
00039 # プロパティの取得には getProperty() 、プロパティのセットには setProperty() と
00040 # いったメソッドを使用することが推奨される。
00041 #
00042 # プロパティをストリームに保存するとき、またはストリームからロードするとき
00043 # に、ISO 8859-1 文字エンコーディングが使用される。このエンコーディングに
00044 # 直接表示できない文字は、扱うことができない。
00045 #
00046 # このクラスは、Java の Properties クラス (java.util.Properties) とほぼ同様の
00047 # メソッドを持つ。また、入出力されるファイルは Java の Properties クラスが
00048 # 出力するものと互換性があるが、Unicode を含むものは扱うことができない。
00049 #
00050 # @since 0.4.0
00051 #
00052 # @else
00053 #
00054 # @class Properties
00055 #
00056 # The Properties class represents a persistent set of properties. The
00057 # Properties can be saved to a stream or loaded from a stream. Each key and
00058 # its corresponding value in the property list is a string. 
00059 #
00060 # A property list can contain another property list as its "defaults"; this
00061 # second property list is searched if the property key is not found in the
00062 # original property list. 
00063 #
00064 # Because Properties inherits from Hashtable, the put and putAll methods can
00065 # be applied to a Properties object. Their use is strongly discouraged as 
00066 # they allow the caller to insert entries whose keys or values are not 
00067 # Strings. The setProperty method should be used instead. If the store or 
00068 # save method is called on a "compromised" Properties object that contains a 
00069 # non-String key or value, the call will fail. 
00070 #
00071 # The load and store methods load and store properties in a simple
00072 # line-oriented format specified below. This format uses the ISO 8859-1
00073 # character encoding. Characters that cannot be directly represented in this
00074 # encoding can be written using Unicode escapes ; only a single 'u' character
00075 # is allowed in an escape sequence. The native2ascii tool can be used to
00076 # convert property files to and from other character encodings. 
00077 #
00078 # This class has almost same methods of Java's Properties class. Input and 
00079 # Output stream of this properties are compatible each other except Unicode
00080 # encoded property file.
00081 #
00082 # @endif
00083 class Properties:
00084   """
00085   """
00086 
00087 
00088 
00089   ##
00090   # @if jp
00091   #
00092   # @brief コンストラクタ
00093   #
00094   # 以下の順に引数をチェックし、インスタンスの生成を行う。
00095   #
00096   # 引数 prop に値が設定されている場合、
00097   # 引数に与えられた Properties のキー、値およびデフォルト値が
00098   # 全てそのままコピーされる。
00099   #
00100   # 引数 key に値が設定されている場合、
00101   # key と value のみを与えて Property のルートノードを作成する。
00102   # 値は全てデフォルト値として設定される。
00103   #
00104   # 引数 defaults_map に値が設定されている場合、
00105   # defaults_map に設定された内容をデフォルト値にもつ Properties を作成する。
00106   # 値は全てデフォルト値として設定される。
00107   # 
00108   # 引数 defaults_str に値が設定されている場合、
00109   # 指定されたデフォルト値を持つ空のプロパティリストを作成する。
00110   # 値は全てデフォルト値として設定される。
00111   # デフォルト値は char* の配列により与えられ、key と value の対になって
00112   # おり、リストの終端は配列の数を表す引数 num か、空文字の key で与えらられ
00113   # なければならない。
00114   # 以下に例を示す。
00115   #
00116   # <pre>
00117   # const char* defaults = {
00118   #     "key1", "value1",
00119   #     "key2", "value2",
00120   #     "key3", "value3",
00121   #     "key4", "value4",
00122   #     "key5", "value5",
00123   #     "" };
00124   # Properties p(defaults);
00125   # // もしくは
00126   # Properties p(defaults, 10);
00127   # </pre>
00128   # 
00129   # @param self
00130   # @param key プロパティのキー(デフォルト値:None)
00131   # @param value プロパティの値(デフォルト値:None)
00132   # @param defaults_map デフォルト値として指定されるmap(デフォルト値:None)
00133   # @param defaults_str デフォルト値を指定する配列(デフォルト値:None)
00134   # @param num デフォルト値を設定する要素数(デフォルト値:None)
00135   # @param prop デフォルト値として指定されるproperty(デフォルト値:None)
00136   # 
00137   # @else
00138   #
00139   # @brief Constructor
00140   #
00141   # All of given Properties's keys, values and default values are copied to
00142   # new Properties.
00143   #
00144   # Creates a root node of Property with root's key and value.
00145   #
00146   # Creates an Properties with default value of std::string map.
00147   #
00148   # Creates an empty property list with the specified defaults.
00149   # The default values are given by array of char*, which should be pairs
00150   # of "key" and "value". The end of list is specified by argument "num",
00151   # which specifies number of array or null character of key.
00152   # The following is an example.
00153   #
00154   # const char* defaults = {
00155   #     "key1", "value1",
00156   #     "key2", "value2",
00157   #     "key3", "value3",
00158   #     "key4", "value4",
00159   #     "key5", "value5",
00160   #     "" };
00161   # Properties p(defaults);
00162   # // or
00163   # Properties p(defaults, 10);
00164   #
00165   # @endif
00166   def __init__(self, key=None, value=None, defaults_map=None, defaults_str=None, num=None, prop=None):
00167     self.default_value = ""
00168     self.root = None
00169     self.empty = ""
00170     self.leaf = []
00171 
00172     # Properties::Properties(const Properties& prop)
00173     if prop:
00174       self.name          = prop.name
00175       self.value         = prop.value
00176       self.default_value = prop.default_value
00177 
00178       keys = prop.propertyNames()
00179       for _key in keys:
00180         node = None
00181         node = prop.getNode(_key)
00182         if node:
00183           self.setDefault(_key, node.default_value)
00184           self.setProperty(_key, node.value)
00185           
00186       return
00187 
00188     # Properties::Properties(const char* key, const char* value)
00189     if key:
00190       self.name = key
00191       if value is None:
00192         self.value = ""
00193       else:
00194         self.value = value
00195       return
00196 
00197     self.name  = ""
00198     self.value = ""
00199 
00200     # Properties::Properties(std::map<std::string, std::string>& defaults)
00201     if defaults_map:
00202       #for i in range(len(defaults_map.items())):
00203       #  self.setDefault(defaults_map.keys()[i], defaults_map.values()[i])
00204       for key, value in defaults_map.items():
00205         self.setDefault(key, value)
00206       return
00207 
00208     if defaults_str:
00209       if num is None:
00210         _num = sys.maxint
00211       else:
00212         _num = num
00213       self.setDefaults(defaults_str, _num)
00214       return
00215 
00216 
00217   ##
00218   # @if jp
00219   # @brief 代入演算子
00220   # 
00221   # 左辺値の Properties のキー、値およびデフォルト値は全て削除され、
00222   # 右辺値の Properties のキー、値およびデフォルト値が全てそのまま
00223   # コピーされる。
00224   # 
00225   # @param self
00226   # @param prop OpenRTM.Properties
00227   # 
00228   # @else
00229   # @brief Assignment operator
00230   # @param self
00231   # @param prop OpenRTM.Properties
00232   # @endif
00233   def assigmentOperator(self, prop):
00234     self.clear()
00235     self.name = prop.name
00236     self.value = prop.value
00237     self.default_value = prop.default_value
00238 
00239     keys = prop.propertyNames()
00240 
00241     for key in keys:
00242       node = None
00243       node = prop.getNode(key)
00244       if node:
00245         self.setDefault(key, node.default_value)
00246         self.setProperty(key, node.value)
00247 
00248     return self
00249 
00250 
00251   ##
00252   # @if jp
00253   #
00254   # @brief デストラクタ
00255   #
00256   # @param self
00257   #
00258   # @else
00259   #
00260   # @brief Destructor
00261   #
00262   # @endif
00263   def __del__(self):
00264     self.clear()
00265     if self.root:
00266       self.root.removeNode(self.name)
00267     return
00268 
00269   #============================================================
00270   # public functions
00271   #============================================================
00272 
00273 
00274   ##
00275   # @if jp
00276   # @brief Name の取得
00277   #
00278   # プロパティの名称を取得する。
00279   #
00280   # @param self
00281   #
00282   # @return プロパティ名
00283   #
00284   # @else
00285   #
00286   # @endif
00287   def getName(self):
00288     return self.name
00289 
00290 
00291   ##
00292   # @if jp
00293   # @brief 値の取得
00294   #
00295   # プロパティの値を取得する。
00296   #
00297   # @param self
00298   #
00299   # @return プロパティ値
00300   #
00301   # @else
00302   #
00303   # @endif
00304   def getValue(self):
00305     return self.value
00306 
00307 
00308   ##
00309   # @if jp
00310   # @brief デフォルト値の取得
00311   #
00312   # プロパティのデフォルト値を取得する。
00313   #
00314   # @param self
00315   #
00316   # @return プロパティデフォルト値
00317   #
00318   # @else
00319   #
00320   # @endif
00321   def getDefaultValue(self):
00322     return self.default_value
00323 
00324 
00325   ##
00326   # @if jp
00327   # @brief 子要素の取得
00328   #
00329   # プロパティの子要素を取得する。
00330   #
00331   # @param self
00332   #
00333   # @return 子要素
00334   #
00335   # @else
00336   #
00337   # @endif
00338   def getLeaf(self):
00339     return self.leaf
00340 
00341 
00342   ##
00343   # @if jp
00344   # @brief ルート要素の取得
00345   #
00346   # プロパティのルート要素を取得する。
00347   #
00348   # @param self
00349   #
00350   # @return ルート要素
00351   #
00352   # @else
00353   #
00354   # @endif
00355   def getRoot(self):
00356     return self.root
00357 
00358 
00359   ##
00360   # @if jp
00361   #
00362   # @brief 指定されたキーを持つプロパティを、プロパティリストから探す
00363   #
00364   # 指定されたキーを持つプロパティを、プロパティリストから探す。
00365   # そのキーがプロパティリストにない場合は、デフォルト値の引数が返される。 
00366   #
00367   # @param self
00368   # @param key プロパティキー
00369   # @param default デフォルト値(デフォルト値:None)
00370   #
00371   # @return 指定されたキー値を持つこのプロパティリストの値
00372   #
00373   # @else
00374   #
00375   # @brief Searches for the property with the specified key in this property
00376   #
00377   # Searches for the property with the specified key in this property list.
00378   # The method returns the default value argument if the property is not 
00379   # found.
00380   #
00381   # @param key the property key
00382   # @param defaultValue a default value. 
00383   #
00384   # @return the value in this property list with the specified key value.
00385   #
00386   # @endif
00387   def getProperty(self, key, default=None):
00388     if default is None:
00389       keys = []
00390       #keys = string.split(key, ".")
00391       self.split(key, ".", keys)
00392 
00393       node = None
00394       node = self._getNode(keys, 0, self)
00395       if node:
00396         if node.value != "":
00397           return node.value
00398         else:
00399           return node.default_value
00400       return self.empty
00401 
00402     else:
00403       value = self.getProperty(key)
00404       if value == "":
00405         return default
00406       else:
00407         return value
00408 
00409 
00410   ##
00411   # @if jp
00412   # @brief 指定されたキーに対してデフォルト値を取得する
00413   #
00414   # 指定されたキーを持つプロパティのデフォルト値を返す。
00415   # 指定されたキーを持つプロパティが存在しない場合には空文字を返す。
00416   #
00417   # @param self
00418   # @param key プロパティキー
00419   #
00420   # @return 指定されたキー値を持つプロパティのデフォルト値
00421   #
00422   # @else
00423   # @brief Set value as the default value to specified key's property
00424   # @endif
00425   def getDefault(self, key):
00426     keys = []
00427     #keys = string.split(key, ".")
00428     self.split(key, ".", keys)
00429     node = None
00430     node = self._getNode(keys, 0, self)
00431     if node:
00432       return node.default_value
00433 
00434     return self.empty
00435 
00436 
00437   ##
00438   # @if jp
00439   #
00440   # @brief Properties に value を key について登録する
00441   #
00442   # Properties に value を key について登録する。
00443   # すでに key に対する値を持っている場合、戻り値に古い値を返す。
00444   #
00445   # @param self
00446   # @param key プロパティリストに配置されるキー
00447   # @param value key に対応する値(デフォルト値:None)
00448   #
00449   # @return プロパティリストの指定されたキーの前の値。それがない場合は null
00450   #
00451   # @else
00452   #
00453   # @brief Sets a value associated with key in the property list
00454   #
00455   # This method sets the "value" associated with "key" in the property list.
00456   # If the property list has a value of "key", old value is returned.
00457   #
00458   # @param key the key to be placed into this property list.
00459   # @param value the value corresponding to key. 
00460   #
00461   # @return the previous value of the specified key in this property list,
00462   #         or null if it did not have one.
00463   #
00464   #@endif
00465   def setProperty(self, key, value=None):
00466     if value is not None:
00467       keys = []
00468       #keys = string.split(key, ".")
00469       self.split(key, ".", keys)
00470       curr = self
00471       for _key in keys:
00472         next = curr.hasKey(_key)
00473         if next is None:
00474           next = OpenRTM.Properties(key=_key)
00475           next.root = curr
00476           curr.leaf.append(next)
00477         curr = next
00478       retval = curr.value
00479       curr.value = value
00480       return retval
00481 
00482     else:
00483       self.setProperty(key, self.getProperty(key))
00484       prop = self.getNode(key)
00485       return prop.value
00486 
00487 
00488   ##
00489   # @if jp
00490   # @brief デフォルト値を登録する
00491   #
00492   # key で指定される要素にデフォルト値を登録する。
00493   #
00494   # @param self
00495   # @param key デフォルト値を登録するプロパティのキー
00496   # @param value 登録されるデフォルト値
00497   #
00498   # @return 指定されたデフォルト値
00499   #
00500   # @else
00501   # @brief Sets a default value associated with key in the property list
00502   # @endif
00503   def setDefault(self, key, value):
00504     keys = []
00505     self.split(key, ".", keys)
00506     #keys = string.split(key, ".")
00507 
00508     curr = self
00509     for _key in keys:
00510       next = curr.hasKey(_key)
00511       if next is None:
00512         next = OpenRTM.Properties(key=_key)
00513         next.root = curr
00514         curr.leaf.append(next)
00515       curr = next
00516     if value != "" and value[-1] == "\n":
00517       value = value[0:len(value)-1]
00518     curr.default_value = value
00519     return value
00520 
00521 
00522   ##
00523   # @if jp
00524   # @brief Properties にデフォルト値をまとめて登録する
00525   #
00526   # 配列で指定された要素にデフォルト値をまとめて登録する。
00527   # デフォルト値は char* の配列により与えられ、key と value の対になって
00528   # おり、リストの終端は配列の数を表す引数 num か、空文字の key で与えらられ
00529   # なければならない。
00530   # 
00531   # @param self
00532   # @param defaults デフォルト値を指定する配列
00533   # @param num デフォルト値を設定する要素数(デフォルト値:None)
00534   # 
00535   # @else
00536   # @brief Sets a default value associated with key in the property list
00537   # @endif
00538   def setDefaults(self, defaults, num = None):
00539     if num is None:
00540       num = sys.maxint
00541 
00542     i = 0
00543     len_ = len(defaults)
00544     while 1:
00545       if i > num or i > (len_ - 1) or defaults[i] == "":
00546         break
00547 
00548       key = [defaults[i]]
00549       value = [defaults[i+1]]
00550 
00551       OpenRTM.eraseHeadBlank(key)
00552       OpenRTM.eraseTailBlank(key)
00553 
00554       OpenRTM.eraseHeadBlank(value)
00555       OpenRTM.eraseTailBlank(value)
00556 
00557       self.setDefault(key[0], value[0])
00558 
00559       i +=2
00560 
00561 
00562 
00563   #============================================================
00564   # load and save functions
00565   #============================================================
00566 
00567   ##
00568   # @if jp
00569   #
00570   # @brief 指定された出力ストリームに、プロパティリストを出力する
00571   #
00572   # 指定された出力ストリームに、プロパティリストを出力する。
00573   # このメソッドは主にデバッグに用いられる。
00574   #
00575   # @param self
00576   # @param out 出力ストリーム
00577   #
00578   # @else
00579   #
00580   # @brief Prints this property list out to the specified output stream
00581   #
00582   # Prints this property list out to the specified output stream.
00583   # This method is useful for debugging.
00584   #
00585   # @param out an output stream.
00586   #
00587   # @endif
00588   def list(self, out):
00589     self._store(out, "", self)
00590     return
00591 
00592 
00593   ##
00594   # @if jp
00595   #
00596   # @brief 入力ストリームからキーと要素が対になったプロパティリストを読み込む
00597   #
00598   # 入力ストリームからキーと要素が対になったプロパティリストを読み込む。
00599   # ストリームは、ISO 8859-1 文字エンコーディングを使用しているとみなされる。
00600   # 各プロパティは、入力ストリームに行単位で登録されているものとみなされ、
00601   # 各行は行区切り文字 (\\n、\\r、または \\r\\n) で終わる。
00602   # 入力ストリームから読み込んだ行は、入力ストリームでファイルの終わりに
00603   # 達するまで処理される。
00604   #
00605   # 空白文字だけの行、または最初の非空白文字が ASCII 文字 # または ! である
00606   # 行は無視される。つまり、# または ! はコメント行を示す。
00607   #
00608   # 空白行またはコメント行以外のすべての行は、テーブルに追加されるプロパティ
00609   # を記述する。ただし、行の終わりが \ の場合は、次の行があれば継続行として
00610   # 扱われる (下記を参照)。 キーは、最初の非空白文字から、最初の ASCII 文字
00611   # =、:、または空白文字の直前までの、行内のすべての文字から構成される。
00612   #
00613   # キーの終わりを示す文字は、前に \ を付けることによりキーに含めることも
00614   # できる。キーの後ろの空白はすべてスキップされる。
00615   # キーの後ろの最初の非空白文字が = または : である場合は、これらのキーは
00616   # 無視され、そのあとの空白文字もすべてスキップされる。
00617   # 行内のそれ以外の文字はすべて、関連した要素文字列の一部となる。
00618   # 要素文字列内では、ASCII エスケープシーケンス \\t、\\n、\\r、\\\\、\\"、
00619   # \\'、\\ (円記号とスペース)、および \\uxxxx は認識され、単独の文字に変換
00620   # される。
00621   # また、行の最後の文字が \ である場合は、次の行は現在の行の継続として
00622   # 扱われる。その場合、\ と行区切り文字が破棄され、継続行の先頭に空白が
00623   # あればそれもすべて破棄され、要素文字列の一部にはならない。 
00624   #
00625   # たとえば、次の 4 行はそれぞれキー Truth と関連した要素値 Beauty を表す。
00626   # 
00627   # Truth = Beauty <BR>
00628   # Truth:Beauty <BR>
00629   # Truth\\t\\t\\t:Beauty <BR>
00630   #
00631   # また、次の 3 行は 1 つのプロパティを表す。 
00632   #
00633   # fruits\\t\\t\\t\\tapple, banana, pear, \ <BR>
00634   #                                  cantaloupe, watermelon, \ <BR>
00635   #                                  kiwi, mango <BR>
00636   # キーは fruits で、次の要素に関連付けれられる。 
00637   # "apple, banana, pear, cantaloupe, watermelon, kiwi, mango"
00638   # 最終的な結果でコンマのあとに必ずスペースが表示されるように、
00639   # 各 \ の前にスペースがある。行の終わりを示す \ と、継続行の先頭にある
00640   # 空白は破棄され、他の文字に置換されない。 
00641   # また、次の 3 番目の例では、キーが cheeses で、関連した要素が空の文字列
00642   # であることを表す。 
00643   #
00644   # cheeses <BR>
00645   # キーは、cheeses で、関連要素は空の文字列であることを指定している。 
00646   #
00647   # @param self
00648   # @param inStream 入力ストリーム 
00649   #
00650   # @else
00651   #
00652   # @brief Loads property list consists of key:value from input stream
00653   #
00654   # Reads a property list (key and element pairs) from the input stream.
00655   # The stream is assumed to be using the ISO 8859-1 character encoding; that
00656   # is each byte is one Latin1 character. Characters not in Latin1, and
00657   # certain special characters, can be represented in keys and elements using
00658   # escape sequences similar to those used for character and string literals
00659   # The differences from the character escape sequences used for characters
00660   # and strings are: 
00661   # - Octal escapes are not recognized. 
00662   # - The character sequence \b does not represent a backspace character. 
00663   # - The method does not treat a backslash character, \, before a non-valid
00664   #   escape character as an error; the backslash is silently dropped. For
00665   #   example, in a Java string the sequence "\z" would cause a compile time
00666   #   error. In contrast, this method silently drops the backslash. 
00667   #   Therefore, this method treats the two character sequence "\b" as 
00668   #   equivalent to the single character 'b'. 
00669   # - Escapes are not necessary for single and double quotes; however, by the
00670   #   rule above, single and double quote characters preceded by a backslash
00671   #   still yield single and double quote characters, respectively. 
00672   # An IllegalArgumentException is thrown if a malformed Unicode escape
00673   # appears in the input. 
00674   #
00675   # This method processes input in terms of lines. A natural line of input is
00676   # terminated either by a set of line terminator characters
00677   # (\n or \r or \r\n) or by the end of the file. A natural line may be 
00678   # either a blank line, a comment line, or hold some part of a key-element 
00679   # pair. The logical line holding all the data for a key-element pair may 
00680   # be spread out across several adjacent natural lines by escaping the line 
00681   # terminator sequence with a backslash character, \. Note that a comment 
00682   # line cannot be extended in this manner; every natural line that is a 
00683   # comment must have its own comment indicator, as described below. If a 
00684   # logical line is continued over several natural lines, the continuation 
00685   # lines receive further processing, also described below. Lines are read 
00686   # from the input stream until end of file is reached. 
00687   #
00688   # A natural line that contains only white space characters is considered
00689   # blank and is ignored. A comment line has an ASCII '#' or '!' as its first
00690   # non-white space character; comment lines are also ignored and do not
00691   # encode key-element information. In addition to line terminators, this
00692   # method considers the characters space (' ', '\u0020'), tab 
00693   # ('\t', '\u0009'), and form feed ('\f', '\u000C') to be white space. 
00694   #
00695   # If a logical line is spread across several natural lines, the backslash
00696   # escaping the line terminator sequence, the line terminator sequence, and
00697   # any white space at the start the following line have no affect on the key
00698   # or element values. The remainder of the discussion of key and element
00699   # parsing will assume all the characters constituting the key and element
00700   # appear on a single natural line after line continuation characters have
00701   # been removed. Note that it is not sufficient to only examine the 
00702   # character preceding a line terminator sequence to see if the line 
00703   # terminator is escaped; there must be an odd number of contiguous 
00704   # backslashes for the line terminator to be escaped. Since the input is 
00705   # processed from left to right, a non-zero even number of 2n contiguous 
00706   # backslashes before a line terminator (or elsewhere) encodes n 
00707   # backslashes after escape processing. 
00708   #
00709   # The key contains all of the characters in the line starting with the 
00710   # first non-white space character and up to, but not including, the first
00711   # unescaped '=', ':', or white space character other than a line 
00712   # terminator. All of these key termination characters may be included in 
00713   # the key by escaping them with a preceding backslash character; 
00714   # for example,
00715   #
00716   # \:\=
00717   #
00718   # would be the two-character key ":=". Line terminator characters can be
00719   # included using \r and \n escape sequences. Any white space after the key
00720   # is skipped; if the first non-white space character after the key is '=' 
00721   # or ':', then it is ignored and any white space characters after it are 
00722   # also skipped. All remaining characters on the line become part of the
00723   # associated element string; if there are no remaining characters, the
00724   # element is the empty string "". Once the raw character sequences
00725   # constituting the key and element are identified, escape processing is
00726   # performed as described above. 
00727   #
00728   # As an example, each of the following three lines specifies the key 
00729   # "Truth" and the associated element value "Beauty": 
00730   #
00731   # Truth = Beauty <BR>
00732   #        Truth:Beauty <BR>
00733   # Truth                  :Beauty <BR>
00734   #  As another example, the following three lines specify a single 
00735   # property: 
00736   #
00737   # fruits                           apple, banana, pear, \ <BR>
00738   #                                  cantaloupe, watermelon, \ <BR>
00739   #                                  kiwi, mango <BR>
00740   # The key is "fruits" and the associated element is: 
00741   # "apple, banana, pear, cantaloupe, watermelon, kiwi, mango"Note that a
00742   # space appears before each \ so that a space will appear after each comma
00743   # in the final result; the \, line terminator, and leading white space on
00744   # the continuation line are merely discarded and are not replaced by one or
00745   # more other characters. 
00746   # As a third example, the line: 
00747   #
00748   # cheeses <BR>
00749   # specifies that the key is "cheeses" and the associated element is the
00750   # empty string "".
00751   #
00752   # @param inStream the input stream.
00753   #
00754   # @endif
00755   def load(self, inStream):
00756     pline = ""
00757     for readStr in inStream:
00758       if readStr is None:
00759         continue
00760       
00761       tmp = [readStr]
00762       OpenRTM.eraseHeadBlank(tmp)
00763       _str = tmp[0]
00764       
00765       if _str[0] == "#" or _str[0] == "!" or _str[0] == "\n":
00766         continue
00767 
00768       if _str[-1] == "\n":
00769         _str = _str[0:len(_str)-1]
00770 
00771       if _str[len(_str)-1] == "\\" and not OpenRTM.isEscaped(_str, len(_str)-1):
00772         #_str = _str[0:len(_str)-1]
00773         tmp = [_str[0:len(_str)-1]]
00774         OpenRTM.eraseTailBlank(tmp)
00775         #pline += _str
00776         pline += tmp[0]
00777         continue
00778       pline += _str
00779       if pline == "":
00780         continue
00781 
00782       key = []
00783       value = []
00784       self.splitKeyValue(pline, key, value)
00785       key[0] = OpenRTM.unescape(key)
00786       OpenRTM.eraseHeadBlank(key)
00787       OpenRTM.eraseTailBlank(key)
00788 
00789       value[0] = OpenRTM.unescape(value)
00790       OpenRTM.eraseHeadBlank(value)
00791       OpenRTM.eraseTailBlank(value)
00792 
00793       self.setProperty(key[0], value[0])
00794       pline = ""
00795 
00796 
00797   ##
00798   # @if jp
00799   #
00800   # @brief プロパティリストを指定されたストリームに保存する
00801   #
00802   # プロパティリストを指定されたストリームに保存する。
00803   # このメソッドは Java Properties との互換性のために定義されている。
00804   # (内部的には store メソッドを利用している。)
00805   #
00806   # @param self
00807   # @param out 出力ストリーム
00808   # @param header プロパティリストの記述 
00809   #
00810   # @else
00811   #
00812   # @brief Save the properties list to the stream
00813   #
00814   # Deprecated. 
00815   #
00816   # @param out The output stream
00817   # @param header A description of the property list
00818   #
00819   # @endif
00820   def save(self, out, header):
00821     self.store(out, header)
00822     return
00823 
00824 
00825   ##
00826   # @if jp
00827   #
00828   # @brief プロパティリストを出力ストリームへ保存する
00829   #
00830   # Properties テーブル内のプロパティリスト (キーと要素のペア) を、load
00831   # メソッドを使って Properties テーブルにロードするのに適切なフォーマットで
00832   # 出力ストリームに書き込む。 
00833   #
00834   # Properties テーブル内のプロパティリスト (キーと要素のペア) を、load
00835   # メソッドを使って Properties テーブルにロードするのに適切なフォーマットで
00836   # 出力ストリームに書き込む。ストリームは、ISO 8859-1 文字
00837   # エンコーディングを使用して書き込まれる。 
00838   # Properties テーブル (存在する場合) のデフォルトテーブルからの
00839   # プロパティは、このメソッドによっては書き込まれない。 
00840   #
00841   # header 引数が null でない場合は、ASCII 文字の #、header の文字列、
00842   # および行区切り文字が最初に出力ストリームに書き込まれます。このため、
00843   # header は識別コメントとして使うことができる。 
00844   #
00845   # 次に、ASCII 文字の #、現在の日時 (Date の toString メソッドによって
00846   # 現在時刻が生成されるのと同様)、および Writer によって生成される行区切り
00847   # からなるコメント行が書き込まれる。 
00848   #
00849   # 続いて、 Properties テーブル内のすべてのエントリが 1 行ずつ書き出される。
00850   # 各エントリのキー文字列、ASCII 文字の=、関連した要素文字列が書き込まれる。
00851   # 要素文字列の各文字は、エスケープシーケンスとして描画する必要があるか
00852   # どうか確認される。ASCII 文字の \、タブ、改行、および復帰はそれぞれ \\\\、
00853   # \\t、\\n、および \\r として書き込まれる。\\u0020 より小さい文字および
00854   # \\u007E より大きい文字は、対応する 16 進値 xxxx を使って \\uxxxx として
00855   # 書き込まれる。埋め込み空白文字でも後書き空白文字でもない先行空白文字は、
00856   # 前に \ を付けて書き込まれる。キーと値の文字 #、!、=、および : は、
00857   # 必ず正しくロードされるように、前にスラッシュを付けて書き込まれる。 
00858   #
00859   # エントリが書き込まれたあとで、出力ストリームがフラッシュされる。
00860   # 出力ストリームはこのメソッドから復帰したあとも開いたままとなる。 
00861   #
00862   # @param self
00863   # @param out 出力ストリーム
00864   # @param header プロパティリストの記述 
00865   #
00866   # @else
00867   #
00868   # @brief Stores property list to the output stream
00869   #
00870   # Writes this property list (key and element pairs) in this Properties 
00871   # table to the output stream in a format suitable for loading into a 
00872   # Properties table using the load method. The stream is written using the 
00873   # ISO 8859-1 character encoding. 
00874   #
00875   # Properties from the defaults table of this Properties table (if any) are
00876   # not written out by this method. 
00877   #
00878   # If the comments argument is not null, then an ASCII # character, the
00879   # comments string, and a line separator are first written to the output
00880   # stream. Thus, the comments can serve as an identifying comment. 
00881   #
00882   # Next, a comment line is always written, consisting of an ASCII #
00883   # character, the current date and time (as if produced by the toString
00884   # method of Date for the current time), and a line separator as generated
00885   # by the Writer. 
00886   #
00887   # Then every entry in this Properties table is written out, one per line.
00888   # For each entry the key string is written, then an ASCII =, then the
00889   # associated element string. Each character of the key and element strings
00890   # is examined to see whether it should be rendered as an escape sequence.
00891   # The ASCII characters \, tab, form feed, newline, and carriage return are
00892   # written as \\, \t, \f \n, and \r, respectively. Characters less than
00893   # \u0020 and characters greater than \u007E are written as \uxxxx for the
00894   # appropriate hexadecimal value xxxx. For the key, all space characters are
00895   # written with a preceding \ character. For the element, leading space
00896   # characters, but not embedded or trailing space characters, are written
00897   # with a preceding \ character. The key and element characters #, !, =, and
00898   # : are written with a preceding backslash to ensure that they are properly
00899   # loaded. 
00900   #
00901   # After the entries have been written, the output stream is flushed. The
00902   # output stream remains open after this method returns. 
00903   #
00904   # @param out an output stream.
00905   # @param header a description of the property list.
00906   #
00907   # @endif
00908   def store(self, out, header):
00909     out.write("#"+header+"\n")
00910     self._store(out, "", self)
00911 
00912 
00913   #============================================================
00914   # other util functions
00915   #============================================================
00916 
00917   ##
00918   # @if jp
00919   #
00920   # @brief プロパティのキーのリストを vector で返す
00921   #
00922   # メインプロパティリストに同じ名前のキーが見つからない場合は、デフォルトの
00923   # プロパティリストにある個別のキーを含む、このプロパティリストにあるすべて
00924   # のキーのリストを返す。 
00925   #
00926   # @param self
00927   #
00928   # @return プロパティリストにあるすべてのキーのリスト。
00929   #         デフォルトのプロパティリストにあるキーを含む
00930   #
00931   # @else
00932   #
00933   # @brief Returns an vector of all the keys in this property
00934   #
00935   # Returns an enumeration of all the keys in this property list, including
00936   # distinct keys in the default property list if a key of the same name has
00937   # not already been found from the main properties list.
00938   #
00939   # @return an vector of all the keys in this property list, including the
00940   #         keys in the default property list.
00941   #
00942   # @endif
00943   def propertyNames(self):
00944     names = []
00945     for leaf in self.leaf:
00946       self._propertiyNames(names, leaf.name, leaf)
00947     return names
00948 
00949 
00950   ##
00951   # @if jp
00952   # @brief プロパティの数を取得する
00953   #
00954   # 設定済みのプロパティ数を取得する。
00955   #
00956   # @param self
00957   #
00958   # @return プロパティ数
00959   #
00960   # @else
00961   # @brief Get number of Properties
00962   # @endif
00963   def size(self):
00964     return len(self.propertyNames())
00965 
00966 
00967   ##
00968   # @if jp
00969   # @brief ノードを取得する
00970   #
00971   # 指定したキーを持つノードを取得する。
00972   #
00973   # @param self
00974   # @param key 取得対象ノードのキー
00975   #
00976   # @return 対象ノード
00977   #
00978   # @else
00979   # @brief Get node of Properties
00980   # @endif
00981   def getNode(self, key):
00982     keys = []
00983     value = ""
00984     self.split(key, ".", keys)
00985     return self._getNode(keys, 0, self)
00986 
00987 
00988   ##
00989   # @if jp
00990   # @brief 新規ノードを生成する
00991   #
00992   # 指定したキーを持つ新規ノードを生成する。
00993   # 既に同一キーを持つノードが登録済みの場合にはエラーを返す。
00994   #
00995   # @param self
00996   # @param key 新規ノードのキー
00997   #
00998   # @return 新規ノード生成結果
00999   #         指定したキーを持つノードが既に存在する場合にはfalse
01000   #
01001   # @else
01002   #
01003   # @endif
01004   def createNode(self, key):
01005     p = self.getNode(key)
01006     if p:
01007       return False
01008     
01009     self.setProperty(key,"")
01010     return True
01011 
01012 
01013   ##
01014   # @if jp
01015   # @brief ノードを削除する
01016   #
01017   # 指定した名称を持つプロパティを削除する。
01018   # 削除したプロパティを返す。
01019   #
01020   # @param self
01021   # @param leaf_name 削除対象プロパティ名称
01022   #
01023   # @return 削除したプロパティ
01024   #
01025   # @else
01026   # @brief Get node of Properties
01027   # @endif
01028   def removeNode(self, leaf_name):
01029     len_ = len(self.leaf)
01030     for i in range(len_):
01031       idx = (len_ - 1) - i
01032       if self.leaf[idx].name == leaf_name:
01033         prop = self.leaf[idx]
01034         del self.leaf[idx]
01035         return prop
01036     return None
01037 
01038 
01039   ##
01040   # @if jp
01041   # @brief 子ノードにkeyがあるかどうか
01042   #
01043   # 指定したキーを持つ子ノードが存在するかどうか確認する。
01044   # 存在する場合、子ノードを返す。
01045   #
01046   # @param self
01047   # @param key 確認対象のキー
01048   #
01049   # @return 子ノード
01050   #
01051   # @else
01052   # @brief If key exists in the children
01053   # @endif
01054   def hasKey(self, key):
01055     for leaf in self.leaf:
01056       if leaf.name == key:
01057         return leaf
01058 
01059     return None
01060 
01061 
01062   ##
01063   # @if jp
01064   # @brief 子ノードを全て削除する
01065   #
01066   # @param self
01067   #
01068   # @else
01069   # @brief If key exists in the children
01070   # @endif
01071   def clear(self):
01072     len_ = len(self.leaf)
01073     for i in range(len_):
01074       if self.leaf[-1]:
01075         del self.leaf[-1]
01076 
01077     return
01078 
01079 
01080   ##
01081   # @if jp
01082   # @brief Propertyをマージする
01083   #
01084   # 現在のプロパティに設定したプロパティをマージする。
01085   #
01086   # @param self
01087   # @param prop マージするプロパティ
01088   #
01089   # @return プロパティマージ結果
01090   #
01091   # @else
01092   # @brief Merge properties
01093   # @endif
01094   def mergeProperties(self, prop):
01095     keys = prop.propertyNames()
01096 
01097     for i in range(prop.size()):
01098       self.setProperty(keys[i], prop.getProperty(keys[i]))
01099 
01100     return self
01101 
01102 
01103   ##
01104   # @if jp
01105   # @brief 文字列をキーと値のペアに分割する
01106   #
01107   # 与えられた文字列を、設定されたデリミタでキーと値のペアに分割する。
01108   # まず最初に与えられた文字列に':'もしくは'='が含まれるかを検索し、
01109   # どちらかの文字が含まれている場合にはそれをデリミタとして使用する。
01110   # 両方とも含まれていない場合には、' '(スペース)を用いて分割を試みる。
01111   # 全てのデリミタ候補が含まれていない場合には、与えられた文字列をキーとして
01112   # 設定し、値に空の文字列を設定する。
01113   # どのデリミタ候補についてもエスケープされている(直前に'\'が設定されている)
01114   # 場合には、デリミタとして使用しない。
01115   #
01116   # @param self
01117   # @param _str 分割対象文字列
01118   # @param key 分割結果キー
01119   # @param value 分割結果値
01120   #
01121   # @else
01122   #
01123   # @endif
01124   def splitKeyValue(self, _str, key, value):
01125     i = 0
01126     length = len(_str)
01127 
01128     while i < length:
01129       if (_str[i] == ":" or _str[i] == "=") and not OpenRTM.isEscaped(_str, i):
01130         key.append(_str[0:i])
01131         value.append(_str[i+1:])
01132         return
01133       i += 1
01134 
01135     # If no ':' or '=' exist, ' ' would be delimiter.
01136     i = 0
01137     while i < length:
01138       if (_str[i] == " ") and not OpenRTM.isEscaped(_str, i):
01139         key.append(_str[0:i])
01140         value.append(_str[i+1:])
01141         return
01142       i += 1
01143 
01144     key.append(_str)
01145     value.append("")
01146     return
01147 
01148 
01149   ##
01150   # @if jp
01151   # @brief 文字列を分割する
01152   #
01153   # 与えられた文字列を、与えられたデリミタで分割する。
01154   # 与えられた文字列が空の場合は、エラーを返す。
01155   # 与えられたデリミタがエスケープされている(直前に'\'が設定されている)場合
01156   # には、デリミタとして使用しない。
01157   #
01158   # @param self
01159   # @param _str 分割対象文字列
01160   # @param delim デリミタ
01161   # @param value 分割結果値リスト
01162   #
01163   # @return 分割処理結果
01164   #
01165   # @else
01166   #
01167   # @endif
01168   def split(self, _str, delim, value):
01169     if _str == "":
01170       return False
01171 
01172     begin_it = end_it = 0
01173 
01174     length = len(_str)
01175 
01176     while end_it < length:
01177       if _str[end_it] == delim and not OpenRTM.isEscaped(_str, end_it):
01178         value.append(_str[begin_it:end_it])
01179         begin_it = end_it + 1
01180       end_it += 1
01181 
01182     value.append(_str[begin_it:end_it])
01183     return True
01184 
01185 
01186   ##
01187   # @if jp
01188   # @brief プロパティを取得する
01189   #
01190   # キーリストで指定されたプロパティを取得する。
01191   # キーリストでは、指定するキーのプロパティでの階層関係をリスト形式で表現
01192   # する。
01193   # 指定したキーリストに該当するプロパティが存在しない場合はNoneを返す。
01194   #
01195   # @param self
01196   # @param keys 取得対象プロパティのキーのリスト表現
01197   # @param index キーリストの階層数
01198   # @param curr 検索対象プロパティ
01199   #
01200   # @return 検索対象プロパティ
01201   #
01202   # @else
01203   #
01204   # @endif
01205   def _getNode(self, keys, index, curr):
01206     next = curr.hasKey(keys[index])
01207 
01208     if next is None:
01209       return None
01210 
01211     if index < (len(keys) - 1):
01212       index+=1
01213       return next._getNode(keys, index, next)
01214     else:
01215       return next
01216 
01217     return None
01218 
01219 
01220   ##
01221   # @if jp
01222   # @brief プロパティの名称リストを取得する
01223   #
01224   # プロパティの名称を'.'区切りで表現したリストを取得する。
01225   #
01226   # @param self
01227   # @param names プロパティの名称リスト
01228   # @param curr_name 現在のプロパティ名
01229   # @param curr 対象プロパティ
01230   #
01231   # @else
01232   #
01233   # @endif
01234   def _propertiyNames(self, names, curr_name, curr):
01235     if len(curr.leaf) > 0:
01236       for i in range(len(curr.leaf)):
01237         next_name = curr_name+"."+curr.leaf[i].name
01238         self._propertiyNames(names, next_name, curr.leaf[i])
01239     else:
01240       names.append(curr_name)
01241 
01242     return
01243 
01244 
01245   ##
01246   # @if jp
01247   # @brief プロパティの名称リストを保存する
01248   #
01249   # プロパティの名称を'.'区切りで表現したリストを保存する。
01250   #
01251   # @param self
01252   # @param out プロパティの名称リスト保存先の出力ストリーム
01253   # @param curr_name 現在のプロパティ名
01254   # @param curr 対象プロパティ
01255   #
01256   # @else
01257   #
01258   # @endif
01259   def _store(self, out, curr_name, curr):
01260     if len(curr.leaf) > 0:
01261       for i in range(len(curr.leaf)):
01262         if curr_name == "":
01263           next_name = curr.leaf[i].name
01264         else:
01265           next_name = curr_name+"."+curr.leaf[i].name
01266         self._store(out, next_name, curr.leaf[i])
01267         
01268     else:
01269       val = curr.value
01270       if val == "":
01271         val = curr.default_value
01272       out.write(curr_name+": "+val+"\n")
01273 
01274     return
01275 
01276 
01277   ##
01278   # @if jp
01279   # @brief インデントを生成する
01280   #
01281   # 指定された数字に従って生成したインデントを返す。
01282   # 返されるインデントは、指定数字×2つの空白。
01283   #
01284   # @param self
01285   # @param index インデント数の指定
01286   #
01287   # @return 生成されたインデント
01288   #
01289   # @else
01290   #
01291   # @endif
01292   def indent(self, index):
01293     space = ""
01294 
01295     for i in range(index-1):
01296       space += "  "
01297 
01298     return space
01299 
01300 
01301   ##
01302   # @if jp
01303   # @brief プロパティの内容を保存する
01304   #
01305   # プロパティに設定された内容を保存する。
01306   # 保存時にはプロパティ階層の深さを表す数字が付加される。
01307   # 値が設定されていないプロパティについては、デフォルト値が出力される。
01308   #
01309   # @param self
01310   # @param out プロパティ内容保存先の出力ストリーム
01311   # @param curr 対象プロパティ
01312   # @param index 現在のプロパティ階層
01313   #
01314   # @else
01315   #
01316   # @endif
01317   def _dump(self, out, curr, index):
01318     if index != 0:
01319       #ut.write(self.indent(index)+"- "+curr.name)
01320       out[0]+=self.indent(index)+"- "+curr.name
01321 
01322     if curr.leaf == []:
01323       if curr.value == "":
01324         #out.write(": "+curr.default_value+"\n")
01325         out[0]+=": "+curr.default_value+"\n"
01326       else:
01327         #out.write(": "+curr.value+"\n")
01328         out[0]+=": "+str(curr.value)+"\n"
01329       return out[0]
01330 
01331     if index != 0:
01332       #out.write("\n")
01333       out[0]+="\n"
01334 
01335     for i in range(len(curr.leaf)):
01336       self._dump(out, curr.leaf[i], index + 1)
01337 
01338     return out[0]
01339 
01340 
01341   ##
01342   # @if jp
01343   # @brief プロパティの内容を出力する
01344   #
01345   # プロパティに設定された内容を出力する。<br>
01346   # friend std::ostream& operator<<(std::ostream& lhs, const Properties& rhs);
01347   # の代わりに、print objにて呼び出し可能とするためのメソッド。
01348   #
01349   # @param self
01350   #
01351   # @return 設定プロパティ文字列表示
01352   #
01353   # @else
01354   #
01355   # @endif
01356   def __str__(self):
01357     string=[""]
01358     return self._dump(string, self, 0)
01359 
01360   

OpenRTMに対してMon Mar 17 15:11:06 2008に生成されました。  doxygen 1.5.4