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