iup_config.e 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. class IUP_CONFIG
  2. -- A group of functions to load, store and save application configuration
  3. -- variables. For example, the list of Recent Files, the last position and size
  4. -- of a dialog, last used parameters in dialogs, etc.
  5. --
  6. -- Each variable has a key name, a value and a group that it belongs to. The
  7. -- file is based on a simple configuration file like ".ini" or ".cfg". Each
  8. -- ground can has more than one key, but all keys in the same group must have
  9. -- different names. Group and Key names can NOT have a period ".". The file
  10. -- syntax is such as:
  11. --
  12. -- [Group]
  13. -- Key=Value
  14. -- Key=Value
  15. -- ...
  16. --
  17. -- Guide
  18. --
  19. -- First create a new configuration database using the "config" constructor. To
  20. -- destroy it use the "destroy" function. Then when the application is started
  21. -- call "load" and when the application is about to close, call "save".
  22. --
  23. -- To retrieve variables use the corresponding get_+++ functions and after they
  24. -- where changed store them using the set_+++ functions.
  25. --
  26. -- The following values are used in features to save/retrieve preferences:
  27. --
  28. -- group: group name of the variable
  29. -- key: key name of the variable
  30. -- id: used when the variable has a sequential number
  31. -- value: value of the variable
  32. -- def: default value of the variable
  33. --
  34. -- The features to retrieve variables returns the variable value or empty
  35. -- string (or 0 for integer and double) if the variable is not set or does not
  36. -- exist. When the variable may not exist you can use the functions with
  37. -- "default" to use a default value.
  38. --
  39. -- Internally the variables are stored as attributes using a "<GROUP>.<KEY>"
  40. -- combination, that's why group and key names can not have periods ".".
  41. inherit
  42. IUP_WIDGET
  43. rename
  44. refresh as config
  45. redefine
  46. execute_recent,
  47. config
  48. end
  49. IUP_WIDGET_INTERNALS
  50. rename
  51. refresh as config
  52. redefine
  53. config
  54. end
  55. create {ANY}
  56. config
  57. feature {ANY}
  58. config
  59. -- Returns a new database where the variables will be stored.
  60. local
  61. a_config: POINTER
  62. do
  63. a_config := int_config
  64. set_widget(a_config)
  65. end
  66. -- Operations
  67. load: INTEGER
  68. -- Loads the configuration file.
  69. -- Returns: an error code. 0= no error; -1=error opening the file;
  70. -- -2=error accessing the file; -3=error during filename construction
  71. --
  72. -- The filename (with path) can be set using a regular attribute called
  73. -- APP_FILENAME.
  74. --
  75. -- But the most interesting is to let the filename to be dynamically
  76. -- constructed using the APP_NAME attribute. In this case APP_FILENAME
  77. -- must not be defined. The file name creation will depend on the system
  78. -- and on its usage.
  79. --
  80. -- There are two defined usages. First, for a User Configuration File, it
  81. -- will be stored on the user Home folder. Second, as an Application
  82. -- Configuration File, it will be stored in the same folder of the
  83. -- executable.
  84. --
  85. -- The User Configuration File is the most common usage. In UNIX, the
  86. -- filename will be "<HOME>/.<APP_NAME>", where "<HOME>" is replaced by
  87. -- the "HOME" environment variable contents, and <APP_NAME> replaced by
  88. -- the APP_NAME attribute value. In Windows, the filename will be
  89. -- "<HOMEDRIVE><HOMEPATH>\<APP_NAME>.cfg", where HOMEDRIVE and HOMEPATH
  90. -- are also obtained from environment variables.
  91. --
  92. -- The Application Configuration File is defined by setting the attribute
  93. -- APP_CONFIG to True (default is False). In this case the attribute
  94. -- APP_PATH must also be set. In UNIX, the filename will be
  95. -- "<APP_PATH>.<APP_NAME>", and in Windows will be
  96. -- "<APP_PATH><APP_NAME>.cfg". Notice that the attribute APP_PATH must
  97. -- contains a folder separator "/" at the end.
  98. --
  99. -- After the functions are called the attribute FILENAME is set
  100. -- reflecting the constructed filename.
  101. --
  102. -- So usually at start up, an application will do:
  103. --
  104. -- cfg: IUP_CONFIG
  105. -- create cfg.config
  106. -- cfg.set_app_name("MyAppName")
  107. -- cfg.load
  108. do
  109. Result := int_load(widget)
  110. end
  111. save: INTEGER
  112. -- Saves the configuration file.
  113. -- Returns: an error code. 0= no error; -1=error opening the file;
  114. -- -2=error accessing the file; -3=error during filename construction
  115. --
  116. -- See the notes at "load" function.
  117. do
  118. Result := int_save(widget)
  119. end
  120. set_recent_file_menu (menu: IUP_MENU;
  121. recent_cb: FUNCTION[TUPLE[IUP_CONFIG], STRING];
  122. max_recent: INTEGER)
  123. -- This function (and the next) store and manage a "Recent Files" menu
  124. -- for the application. Call "set_recent_file_menu" once to initialize the
  125. -- menu. Then every time a file is open or saved call
  126. -- "update_recent_file_list" so that the menu list is updated. The last
  127. -- file will be always on the top of the list.
  128. --
  129. -- Inside the RECENT_CB callback the TITLE attribute contains the
  130. -- filename, but the ih object is not the menu, it is the
  131. -- IUP_CONFIG object. But also inside the callback the IUP_CONFIG will
  132. -- inherit attributes from the menu as if it was its parent.
  133. --
  134. -- menu: menu where the recent file items will be listed
  135. -- recent_cb: agent that will be called when a recent file item is
  136. -- selected on the menu
  137. -- max_recent: the maximum number of recent file items.
  138. do
  139. cb_recent := recent_cb
  140. int_config_recent_init(widget, menu.widget, max_recent)
  141. end
  142. set_recent_file_list (list: IUP_LIST;
  143. recent_cb: FUNCTION[TUPLE[IUP_CONFIG], STRING];
  144. max_recent: INTEGER)
  145. -- This function store and manage a "Recent Files" list for the
  146. -- application. Call "set_recent_file_list" once to initialize the
  147. -- list. Then every time a file is open or saved call
  148. -- "update_recent_file_list" so that the list is updated. The last
  149. -- file will be always on the top of the list.
  150. --
  151. -- Inside the RECENT_CB callback the TITLE attribute contains the
  152. -- filename, but the ih object is not the list, it is the
  153. -- IUP_CONFIG object. But also inside the callback the IUP_CONFIG will
  154. -- inherit attributes from the list as if it was its parent.
  155. --
  156. -- list: list where the recent file items will be listed
  157. -- recent_cb: agent that will be called when a recent file item is
  158. -- selected on the list
  159. -- max_recent: the maximum number of recent file items.
  160. do
  161. cb_recent := recent_cb
  162. int_config_recent_init(widget, list.widget, max_recent)
  163. end
  164. update_recent_file_list (filename: STRING)
  165. -- Update the recent file menu list.
  166. --
  167. -- filename: name of the file that where just saved or open
  168. do
  169. int_config_recent_update(widget, get_pointer(filename.to_c))
  170. end
  171. show_dialog (dialog: IUP_WIDGET; name: STRING)
  172. -- This function (and next) store and manage the position and size of a
  173. -- dialog. So when the application is run again the dialog can be show at
  174. -- its last position and last size. Use this function to show the dialog
  175. -- adjusting its size and position. And use the function
  176. -- save_dialog_position to save the last dialog position and size when
  177. -- the dialog is about to be closed, usually inside the dialog CLOSE_CB
  178. -- callback.
  179. --
  180. -- load_dialog_position does no adjustments if the dialog is already
  181. -- visible, just call "show". If the dialog was closed maximized it will
  182. -- be shown maximized. The default size, at the first time ever the
  183. -- dialog is shown, is maximized. The dialog size is set only if
  184. -- RESIZE=True.
  185. --
  186. -- The position is saved in the variables "X" and "Y" of the given group
  187. -- name. The size is saved in the variables "Width" and "Height" of the
  188. -- given group name.
  189. --
  190. -- If your dialog is resizable and you want to avoid the last size usage
  191. -- because you changed the dialog layout, then reset the "Width" and
  192. -- "Height" variables before calling "load_dialog_position".
  193. --
  194. -- To avoid the dialog size to be maximized, set the variable "Maximized"
  195. -- to 0 before calling "load_dialog_position".
  196. --
  197. -- To use "load_dialog_position" for a modal dialog, call it before
  198. -- calling "popup".
  199. --
  200. -- dialog: the dialog to manage the size and position
  201. -- name: a name for this dialog
  202. do
  203. int_config_dialog_show (widget, dialog.widget, get_pointer(name.to_c))
  204. end
  205. save_dialog (dialog: IUP_WIDGET; name: STRING)
  206. -- To save the last dialog position and size when the dialog is about to
  207. -- be closed, usually inside the dialog CLOSE_CB callback.
  208. --
  209. -- dialog: the dialog to manage the size and position
  210. -- name: a name for this dialog
  211. do
  212. int_config_dialog_closed (widget, dialog.widget, get_pointer(name.to_c))
  213. end
  214. -- Attributes
  215. set_app_config (state: BOOLEAN)
  216. -- Set to True to define an Application Configuration File.
  217. do
  218. iup_open.set_attribute(Current, "APP_CONFIG", boolean_to_yesno(state))
  219. end
  220. set_app_system_path (state: BOOLEAN)
  221. -- If set to True, then it will use the system defined folder for
  222. -- application files, in Windows will be the same folder given by the
  223. -- environment variables with "Application Data\" or "AppData\Roaming\"
  224. -- appended.
  225. do
  226. iup_open.set_attribute(Current, "APP_SYSTEMPATH", boolean_to_yesno(state))
  227. end
  228. set_app_file_name (file_name: STRING)
  229. -- The name to the configuration file.
  230. do
  231. iup_open.set_attribute(Current, "APP_FILENAME", file_name)
  232. end
  233. set_app_name (app_name: STRING)
  234. -- The name of the app, in this case APP_FILE_NAME must not be defined.
  235. do
  236. iup_open.set_attribute(Current, "APP_NAME", app_name)
  237. end
  238. set_app_path (app_path: STRING)
  239. -- For Application Configuration File this attribute must also be set.
  240. -- This is the path of the executable folder.
  241. -- Notice that the path must contains a folder separator "/" at the end.
  242. do
  243. iup_open.set_attribute(Current, "APP_PATH", app_path)
  244. end
  245. get_file_name: STRING
  246. -- Path and name of the configuration file.
  247. do
  248. Result := iup_open.get_attribute(Current, "FILENAME")
  249. end
  250. get_title: STRING
  251. -- The selected file at recent menu (only inside RECENT_CB callback).
  252. do
  253. Result := iup_open.get_attribute(Current, "TITLE")
  254. end
  255. -- To store application preferences.
  256. set_variable_string (group, key, value: STRING)
  257. do
  258. int_set_variable_str (widget, get_pointer(group.to_c), get_pointer(key.to_c),
  259. get_pointer(value.to_c))
  260. end
  261. set_variable_string_id (group, key: STRING; id: INTEGER; value: STRING)
  262. do
  263. int_set_variable_str_id (widget, get_pointer(group.to_c), get_pointer(key.to_c),
  264. id, get_pointer(value.to_c))
  265. end
  266. set_variable_integer (group, key: STRING; value: INTEGER)
  267. do
  268. int_set_variable_int (widget, get_pointer(group.to_c), get_pointer(key.to_c),
  269. value)
  270. end
  271. set_variable_integer_id (group, key: STRING; id, value: INTEGER)
  272. do
  273. int_set_variable_int_id (widget, get_pointer(group.to_c), get_pointer(key.to_c),
  274. id, value)
  275. end
  276. set_variable_double (group, key: STRING; value: REAL_64)
  277. do
  278. int_set_variable_double (widget, get_pointer(group.to_c), get_pointer(key.to_c),
  279. value)
  280. end
  281. set_variable_double_id (group, key: STRING; id: INTEGER; value: REAL_64)
  282. do
  283. int_set_variable_double_id (widget, get_pointer(group.to_c),
  284. get_pointer(key.to_c), id, value)
  285. end
  286. -- To retrieve application preferences
  287. get_variable_string (group, key: STRING): STRING
  288. local
  289. p: POINTER
  290. str: STRING
  291. do
  292. p := int_get_variable_str (widget,
  293. get_pointer(group.to_c),
  294. get_pointer(key.to_c))
  295. if p /= default_pointer then
  296. create str.make_from_c(p)
  297. Result := str
  298. else
  299. Result := ""
  300. end
  301. end
  302. get_variable_string_id (group, key: STRING; id: INTEGER): STRING
  303. local
  304. p: POINTER
  305. str: STRING
  306. do
  307. p := int_get_variable_str_id (widget, get_pointer(group.to_c),
  308. get_pointer(key.to_c), id)
  309. if p /= default_pointer then
  310. create str.make_from_c(p)
  311. Result := str
  312. else
  313. Result := ""
  314. end
  315. end
  316. get_variable_integer (group, key: STRING): INTEGER
  317. do
  318. Result := int_get_variable_int (widget, get_pointer(group.to_c),
  319. get_pointer(key.to_c))
  320. end
  321. get_variable_integer_id (group, key: STRING; id: INTEGER): INTEGER
  322. do
  323. Result := int_get_variable_int_id (widget, get_pointer(group.to_c),
  324. get_pointer(key.to_c), id)
  325. end
  326. get_variable_double (group, key: STRING): REAL_64
  327. do
  328. Result := int_get_variable_double (widget, get_pointer(group.to_c),
  329. get_pointer(key.to_c))
  330. end
  331. get_variable_double_id (group, key: STRING; id: INTEGER): REAL_64
  332. do
  333. Result := int_get_variable_double_id (widget, get_pointer(group.to_c),
  334. get_pointer(key.to_c), id)
  335. end
  336. -- To retrieve application preferences with default values
  337. get_variable_string_default (group, key, def: STRING): STRING
  338. local
  339. p: POINTER
  340. str: STRING
  341. do
  342. p := int_get_variable_str_def (widget, get_pointer(group.to_c),
  343. get_pointer(key.to_c),
  344. get_pointer(def.to_c))
  345. if p /= default_pointer then
  346. create str.make_from_c(p)
  347. Result := str
  348. else
  349. Result := ""
  350. end
  351. end
  352. get_variable_string_id_default (group, key: STRING; id: INTEGER;
  353. def: STRING): STRING
  354. local
  355. p: POINTER
  356. str: STRING
  357. do
  358. p := int_get_variable_str_id_def (widget, get_pointer(group.to_c),
  359. get_pointer(key.to_c), id,
  360. get_pointer(def.to_c))
  361. if p /= default_pointer then
  362. create str.make_from_c(p)
  363. Result := str
  364. else
  365. Result := ""
  366. end
  367. end
  368. get_variable_integer_default (group, key: STRING; def: INTEGER): INTEGER
  369. do
  370. Result := int_get_variable_int_def (widget, get_pointer(group.to_c),
  371. get_pointer(key.to_c), def)
  372. end
  373. get_variable_integer_id_default (group, key: STRING; id, def: INTEGER): INTEGER
  374. do
  375. Result := int_get_variable_int_id_def (widget, get_pointer(group.to_c),
  376. get_pointer(key.to_c), id, def)
  377. end
  378. get_variable_double_default (group, key: STRING; def: REAL_64): REAL_64
  379. do
  380. Result := int_get_variable_double_def (widget, get_pointer(group.to_c),
  381. get_pointer(key.to_c), def)
  382. end
  383. get_variable_double_id_default (group, key: STRING; id: INTEGER;
  384. def: REAL_64): REAL_64
  385. do
  386. Result := int_get_variable_double_id_def (widget, get_pointer(group.to_c),
  387. get_pointer(key.to_c), id, def)
  388. end
  389. feature {IUP}
  390. execute_recent: STRING
  391. do
  392. if attached cb_recent as int_cb then
  393. Result := int_cb.item([Current])
  394. else
  395. Result := "IUP_DEFAULT"
  396. end
  397. end
  398. feature {NONE}
  399. cb_recent: detachable FUNCTION[TUPLE[IUP_CONFIG], STRING]
  400. -- Internals
  401. int_config: POINTER
  402. external
  403. "C inline use %"eiffel-iup.h%""
  404. alias
  405. "return IupConfig();"
  406. end
  407. int_load (wgt: POINTER): INTEGER
  408. external
  409. "C inline use %"eiffel-iup.h%""
  410. alias
  411. "return IupConfigLoad ($wgt);"
  412. end
  413. int_save (wgt: POINTER): INTEGER
  414. external
  415. "C inline use %"eiffel-iup.h%""
  416. alias
  417. "return IupConfigSave ($wgt);"
  418. end
  419. int_config_recent_init (wgt, menu: POINTER; max_recent: INTEGER)
  420. external
  421. "C inline use %"eiffel-iup.h%""
  422. alias
  423. "config_recent_init ($wgt, $menu, $max_recent);"
  424. end
  425. int_config_recent_update (wgt, filename: POINTER)
  426. external
  427. "C inline use %"eiffel-iup.h%""
  428. alias
  429. "IupConfigRecentUpdate ($wgt, $filename);"
  430. end
  431. int_config_dialog_show (wgt, dialog, name: POINTER)
  432. external
  433. "C inline use %"eiffel-iup.h%""
  434. alias
  435. "IupConfigDialogShow ($wgt, $dialog, $name);"
  436. end
  437. int_config_dialog_closed (wgt, dialog, name: POINTER)
  438. external
  439. "C inline use %"eiffel-iup.h%""
  440. alias
  441. "IupConfigDialogClosed ($wgt, $dialog, $name);"
  442. end
  443. -- Set variables
  444. int_set_variable_str (wgt, group, key, value: POINTER)
  445. external
  446. "C inline use %"eiffel-iup.h%""
  447. alias
  448. "IupConfigSetVariableStr ($wgt, $group, $key, $value);"
  449. end
  450. int_set_variable_str_id (wgt, group, key: POINTER; id: INTEGER; value: POINTER)
  451. external
  452. "C inline use %"eiffel-iup.h%""
  453. alias
  454. "IupConfigSetVariableStrId ($wgt, $group, $key, $id, $value);"
  455. end
  456. int_set_variable_int (wgt, group, key: POINTER; value: INTEGER)
  457. external
  458. "C inline use %"eiffel-iup.h%""
  459. alias
  460. "IupConfigSetVariableInt ($wgt, $group, $key, $value);"
  461. end
  462. int_set_variable_int_id (wgt, group, key: POINTER; id, value: INTEGER)
  463. external
  464. "C inline use %"eiffel-iup.h%""
  465. alias
  466. "IupConfigSetVariableIntId ($wgt, $group, $key, $id, $value);"
  467. end
  468. int_set_variable_double (wgt, group, key: POINTER; value: REAL_64)
  469. external
  470. "C inline use %"eiffel-iup.h%""
  471. alias
  472. "IupConfigSetVariableDouble ($wgt, $group, $key, $value);"
  473. end
  474. int_set_variable_double_id (wgt, group, key: POINTER; id: INTEGER; value: REAL_64)
  475. external
  476. "C inline use %"eiffel-iup.h%""
  477. alias
  478. "IupConfigSetVariableDoubleId ($wgt, $group, $key, $id, $value);"
  479. end
  480. -- Get variables
  481. int_get_variable_str (wgt, group, key: POINTER): POINTER
  482. external
  483. "C inline use %"eiffel-iup.h%""
  484. alias
  485. "return unconst_char(IupConfigGetVariableStr ($wgt, $group, $key));"
  486. end
  487. int_get_variable_str_id (wgt, group, key: POINTER; id: INTEGER): POINTER
  488. external
  489. "C inline use %"eiffel-iup.h%""
  490. alias
  491. "return unconst_char(IupConfigGetVariableStrId ($wgt, $group, $key, $id));"
  492. end
  493. int_get_variable_int (wgt, group, key: POINTER): INTEGER
  494. external
  495. "C inline use %"eiffel-iup.h%""
  496. alias
  497. "return IupConfigGetVariableInt ($wgt, $group, $key);"
  498. end
  499. int_get_variable_int_id (wgt, group, key: POINTER; id: INTEGER): INTEGER
  500. external
  501. "C inline use %"eiffel-iup.h%""
  502. alias
  503. "return IupConfigGetVariableIntId ($wgt, $group, $key, $id);"
  504. end
  505. int_get_variable_double (wgt, group, key: POINTER): REAL_64
  506. external
  507. "C inline use %"eiffel-iup.h%""
  508. alias
  509. "return IupConfigGetVariableDouble ($wgt, $group, $key);"
  510. end
  511. int_get_variable_double_id (wgt, group, key: POINTER; id: INTEGER): REAL_64
  512. external
  513. "C inline use %"eiffel-iup.h%""
  514. alias
  515. "return IupConfigGetVariableDoubleId ($wgt, $group, $key, $id);"
  516. end
  517. -- Get default variables
  518. int_get_variable_str_def (wgt, group, key, def: POINTER): POINTER
  519. external
  520. "C inline use %"eiffel-iup.h%""
  521. alias
  522. "return unconst_char(IupConfigGetVariableStrDef ($wgt, $group, $key, $def));"
  523. end
  524. int_get_variable_str_id_def (wgt, group, key: POINTER; id: INTEGER; def: POINTER): POINTER
  525. external
  526. "C inline use %"eiffel-iup.h%""
  527. alias
  528. "return unconst_char(IupConfigGetVariableStrIdDef ($wgt, $group, $key, $id, $def));"
  529. end
  530. int_get_variable_int_def (wgt, group, key: POINTER; def: INTEGER): INTEGER
  531. external
  532. "C inline use %"eiffel-iup.h%""
  533. alias
  534. "return IupConfigGetVariableIntDef ($wgt, $group, $key, $def);"
  535. end
  536. int_get_variable_int_id_def (wgt, group, key: POINTER; id, def: INTEGER): INTEGER
  537. external
  538. "C inline use %"eiffel-iup.h%""
  539. alias
  540. "return IupConfigGetVariableIntIdDef ($wgt, $group, $key, $id, $def);"
  541. end
  542. int_get_variable_double_def (wgt, group, key: POINTER; def: REAL_64): REAL_64
  543. external
  544. "C inline use %"eiffel-iup.h%""
  545. alias
  546. "return IupConfigGetVariableDoubleDef ($wgt, $group, $key, $def);"
  547. end
  548. int_get_variable_double_id_def (wgt, group, key: POINTER; id: INTEGER; def: REAL_64): REAL_64
  549. external
  550. "C inline use %"eiffel-iup.h%""
  551. alias
  552. "return IupConfigGetVariableDoubleIdDef ($wgt, $group, $key, $id, $def);"
  553. end
  554. end
  555. -- The MIT License (MIT)
  556. -- Copyright (c) 2016, 2018, 2019, 2020 by German A. Arias
  557. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  558. -- of this software and associated documentation files (the "Software"), to deal
  559. -- in the Software without restriction, including without limitation the rights
  560. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  561. -- copies of the Software, and to permit persons to whom the Software is
  562. -- furnished to do so, subject to the following conditions:
  563. --
  564. -- The above copyright notice and this permission notice shall be included in
  565. -- all copies or substantial portions of the Software.
  566. --
  567. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  568. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  569. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  570. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  571. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  572. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  573. -- SOFTWARE.