From f95cbd8be7345900d4169f93448e574e8327dd49 Mon Sep 17 00:00:00 2001 From: Attila Kovacs Date: Sat, 14 Sep 2024 13:43:52 +0200 Subject: [PATCH] Initial site --- Gemfile | 7 + LICENSE | 24 + _config.yml | 27 + _includes/head-custom-google-analytics.html | 11 + _includes/head-custom.html | 16 + _includes/site.webmanifest | 1 + _sass/jekyll-theme-tactile.scss | 383 ++ apidoc/html/annotated.html | 119 + apidoc/html/annotated_dup.js | 8 + apidoc/html/bc_s.png | Bin 0 -> 633 bytes apidoc/html/bc_sd.png | Bin 0 -> 584 bytes apidoc/html/classes.html | 116 + apidoc/html/clipboard.js | 61 + apidoc/html/closed.png | Bin 0 -> 125 bytes apidoc/html/cookie.js | 58 + apidoc/html/darkmode_toggle.js | 222 + .../dir_68267d1309a1af8e8297ef4c3efbcdba.html | 139 + .../dir_68267d1309a1af8e8297ef4c3efbcdba.js | 11 + .../dir_d44c64559bbebec7f509842c48db8b23.html | 120 + .../dir_d44c64559bbebec7f509842c48db8b23.js | 5 + apidoc/html/doc.svg | 12 + apidoc/html/docd.svg | 12 + apidoc/html/doxygen.css | 2205 +++++++ apidoc/html/doxygen.svg | 28 + apidoc/html/doxygen_crawl.html | 75 + apidoc/html/doxygen_extra.css | 181 + apidoc/html/dynsections.js | 194 + apidoc/html/files.html | 126 + apidoc/html/files_dup.js | 5 + apidoc/html/folderclosed.svg | 11 + apidoc/html/folderclosedd.svg | 11 + apidoc/html/folderopen.svg | 17 + apidoc/html/folderopend.svg | 12 + apidoc/html/functions.html | 130 + apidoc/html/functions_vars.html | 130 + apidoc/html/globals.html | 112 + apidoc/html/globals_defs.html | 159 + apidoc/html/globals_dup.js | 10 + apidoc/html/globals_func.html | 256 + apidoc/html/globals_func.js | 5 + apidoc/html/globals_func_x.html | 113 + apidoc/html/globals_g.html | 112 + apidoc/html/globals_h.html | 114 + apidoc/html/globals_m.html | 116 + apidoc/html/globals_r.html | 112 + apidoc/html/globals_s.html | 280 + apidoc/html/globals_vars.html | 113 + apidoc/html/globals_x.html | 114 + apidoc/html/index.html | 564 ++ apidoc/html/jquery.js | 34 + apidoc/html/md_CHANGELOG.html | 116 + apidoc/html/md_CONTRIBUTING.html | 124 + apidoc/html/menu.js | 134 + apidoc/html/menudata.js | 54 + apidoc/html/minus.svg | 8 + apidoc/html/minusd.svg | 8 + apidoc/html/nav_f.png | Bin 0 -> 130 bytes apidoc/html/nav_fd.png | Bin 0 -> 132 bytes apidoc/html/nav_g.png | Bin 0 -> 95 bytes apidoc/html/nav_h.png | Bin 0 -> 87 bytes apidoc/html/nav_hd.png | Bin 0 -> 98 bytes apidoc/html/navtree.css | 149 + apidoc/html/navtree.js | 482 ++ apidoc/html/navtreedata.js | 96 + apidoc/html/navtreeindex0.js | 253 + apidoc/html/navtreeindex1.js | 174 + apidoc/html/open.png | Bin 0 -> 115 bytes apidoc/html/pages.html | 116 + apidoc/html/plugin.xml | 6 + apidoc/html/plus.svg | 9 + apidoc/html/plusd.svg | 9 + apidoc/html/resize.js | 109 + apidoc/html/search/all_0.js | 4 + apidoc/html/search/all_1.js | 9 + apidoc/html/search/all_10.js | 7 + apidoc/html/search/all_11.js | 202 + apidoc/html/search/all_12.js | 12 + apidoc/html/search/all_13.js | 9 + apidoc/html/search/all_14.js | 4 + apidoc/html/search/all_15.js | 5 + apidoc/html/search/all_16.js | 13 + apidoc/html/search/all_2.js | 5 + apidoc/html/search/all_3.js | 15 + apidoc/html/search/all_4.js | 8 + apidoc/html/search/all_5.js | 5 + apidoc/html/search/all_6.js | 9 + apidoc/html/search/all_7.js | 4 + apidoc/html/search/all_8.js | 11 + apidoc/html/search/all_9.js | 6 + apidoc/html/search/all_a.js | 6 + apidoc/html/search/all_b.js | 11 + apidoc/html/search/all_c.js | 6 + apidoc/html/search/all_d.js | 6 + apidoc/html/search/all_e.js | 12 + apidoc/html/search/all_f.js | 5 + apidoc/html/search/classes_0.js | 8 + apidoc/html/search/close.svg | 18 + apidoc/html/search/defines_0.js | 4 + apidoc/html/search/defines_1.js | 8 + apidoc/html/search/defines_2.js | 4 + apidoc/html/search/defines_3.js | 27 + apidoc/html/search/defines_4.js | 4 + apidoc/html/search/files_0.js | 13 + apidoc/html/search/functions_0.js | 148 + apidoc/html/search/functions_1.js | 5 + apidoc/html/search/mag.svg | 24 + apidoc/html/search/mag_d.svg | 24 + apidoc/html/search/mag_sel.svg | 31 + apidoc/html/search/mag_seld.svg | 31 + apidoc/html/search/pages_0.js | 6 + apidoc/html/search/pages_1.js | 4 + apidoc/html/search/pages_2.js | 4 + apidoc/html/search/pages_3.js | 4 + apidoc/html/search/search.css | 291 + apidoc/html/search/search.js | 694 ++ apidoc/html/search/searchdata.js | 33 + apidoc/html/search/variables_0.js | 4 + apidoc/html/search/variables_1.js | 4 + apidoc/html/search/variables_2.js | 7 + apidoc/html/search/variables_3.js | 4 + apidoc/html/search/variables_4.js | 4 + apidoc/html/search/variables_5.js | 5 + apidoc/html/search/variables_6.js | 4 + apidoc/html/search/variables_7.js | 4 + apidoc/html/search/variables_8.js | 5 + apidoc/html/search/variables_9.js | 10 + apidoc/html/search/variables_a.js | 6 + apidoc/html/search/variables_b.js | 4 + apidoc/html/smax-easy_8c.html | 1843 ++++++ apidoc/html/smax-easy_8c.js | 42 + apidoc/html/smax-lazy_8c.html | 620 ++ apidoc/html/smax-lazy_8c.js | 15 + apidoc/html/smax-messages_8c.html | 498 ++ apidoc/html/smax-messages_8c.js | 16 + apidoc/html/smax-meta_8c.html | 668 ++ apidoc/html/smax-meta_8c.js | 17 + apidoc/html/smax-private_8h.html | 132 + apidoc/html/smax-private_8h.js | 5 + apidoc/html/smax-queue_8c.html | 377 ++ apidoc/html/smax-queue_8c.js | 10 + apidoc/html/smax-resilient_8c.html | 212 + apidoc/html/smax-resilient_8c.js | 6 + apidoc/html/smax-util_8c.html | 1024 +++ apidoc/html/smax-util_8c.js | 29 + apidoc/html/smax_8c.html | 1348 ++++ apidoc/html/smax_8c.js | 42 + apidoc/html/smax_8h.html | 5724 +++++++++++++++++ apidoc/html/smax_8h.js | 180 + apidoc/html/smithsonian-logo-55x55.png | Bin 0 -> 5834 bytes apidoc/html/splitbar.png | Bin 0 -> 283 bytes apidoc/html/splitbard.png | Bin 0 -> 266 bytes apidoc/html/structXCoordinateAxis.html | 148 + apidoc/html/structXCoordinateAxis.js | 8 + apidoc/html/structXCoordinateSystem.html | 138 + apidoc/html/structXCoordinateSystem.js | 5 + apidoc/html/structXMessage.html | 147 + apidoc/html/structXMessage.js | 8 + apidoc/html/structXMeta.html | 160 + apidoc/html/structXMeta.js | 11 + apidoc/html/structXSyncPoint.html | 144 + apidoc/html/structXSyncPoint.js | 6 + apidoc/html/sync_off.png | Bin 0 -> 814 bytes apidoc/html/sync_on.png | Bin 0 -> 810 bytes apidoc/html/tab_a.png | Bin 0 -> 124 bytes apidoc/html/tab_ad.png | Bin 0 -> 119 bytes apidoc/html/tab_b.png | Bin 0 -> 142 bytes apidoc/html/tab_bd.png | Bin 0 -> 140 bytes apidoc/html/tab_h.png | Bin 0 -> 147 bytes apidoc/html/tab_hd.png | Bin 0 -> 148 bytes apidoc/html/tab_s.png | Bin 0 -> 161 bytes apidoc/html/tab_sd.png | Bin 0 -> 159 bytes apidoc/html/tabs.css | 1 + apidoc/html/toc.xml | 490 ++ apidoc/man/man3/XCoordinateAxis.3 | 51 + apidoc/man/man3/XCoordinateSystem.3 | 41 + apidoc/man/man3/XMessage.3 | 42 + apidoc/man/man3/XMeta.3 | 63 + apidoc/man/man3/XSyncPoint.3 | 47 + apidoc/man/man3/md_CHANGELOG.3 | 12 + apidoc/man/man3/md_CONTRIBUTING.3 | 27 + apidoc/man/man3/smax-easy.c.3 | 1203 ++++ apidoc/man/man3/smax-lazy.c.3 | 368 ++ apidoc/man/man3/smax-messages.c.3 | 297 + apidoc/man/man3/smax-meta.c.3 | 414 ++ apidoc/man/man3/smax-private.h.3 | 41 + apidoc/man/man3/smax-queue.c.3 | 211 + apidoc/man/man3/smax-resilient.c.3 | 104 + apidoc/man/man3/smax-util.c.3 | 617 ++ apidoc/man/man3/smax.c.3 | 959 +++ apidoc/man/man3/smax.h.3 | 3956 ++++++++++++ apidoc/smax.tag | 2576 ++++++++ doc/CHANGELOG.md | 12 + doc/README.md | 730 +++ doc/resources | 1 + favicon.ico | Bin 0 -> 15406 bytes index.md | 41 + resources/CHANGELOG.md | 12 + resources/CfA-logo.png | Bin 0 -> 66776 bytes resources/README.md | 751 +++ resources/android-chrome-192x192.png | Bin 0 -> 27463 bytes resources/android-chrome-512x512.png | Bin 0 -> 113748 bytes resources/apple-touch-icon.png | Bin 0 -> 24723 bytes resources/favicon-16x16.png | Bin 0 -> 863 bytes resources/favicon-32x32.png | Bin 0 -> 2203 bytes resources/favicon.ico | Bin 0 -> 15406 bytes resources/smithsonian-logo.png | Bin 0 -> 13216 bytes 206 files changed, 37008 insertions(+) create mode 100644 Gemfile create mode 100644 LICENSE create mode 100644 _config.yml create mode 100644 _includes/head-custom-google-analytics.html create mode 100644 _includes/head-custom.html create mode 100644 _includes/site.webmanifest create mode 100644 _sass/jekyll-theme-tactile.scss create mode 100644 apidoc/html/annotated.html create mode 100644 apidoc/html/annotated_dup.js create mode 100644 apidoc/html/bc_s.png create mode 100644 apidoc/html/bc_sd.png create mode 100644 apidoc/html/classes.html create mode 100644 apidoc/html/clipboard.js create mode 100644 apidoc/html/closed.png create mode 100644 apidoc/html/cookie.js create mode 100644 apidoc/html/darkmode_toggle.js create mode 100644 apidoc/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html create mode 100644 apidoc/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js create mode 100644 apidoc/html/dir_d44c64559bbebec7f509842c48db8b23.html create mode 100644 apidoc/html/dir_d44c64559bbebec7f509842c48db8b23.js create mode 100644 apidoc/html/doc.svg create mode 100644 apidoc/html/docd.svg create mode 100644 apidoc/html/doxygen.css create mode 100644 apidoc/html/doxygen.svg create mode 100644 apidoc/html/doxygen_crawl.html create mode 100644 apidoc/html/doxygen_extra.css create mode 100644 apidoc/html/dynsections.js create mode 100644 apidoc/html/files.html create mode 100644 apidoc/html/files_dup.js create mode 100644 apidoc/html/folderclosed.svg create mode 100644 apidoc/html/folderclosedd.svg create mode 100644 apidoc/html/folderopen.svg create mode 100644 apidoc/html/folderopend.svg create mode 100644 apidoc/html/functions.html create mode 100644 apidoc/html/functions_vars.html create mode 100644 apidoc/html/globals.html create mode 100644 apidoc/html/globals_defs.html create mode 100644 apidoc/html/globals_dup.js create mode 100644 apidoc/html/globals_func.html create mode 100644 apidoc/html/globals_func.js create mode 100644 apidoc/html/globals_func_x.html create mode 100644 apidoc/html/globals_g.html create mode 100644 apidoc/html/globals_h.html create mode 100644 apidoc/html/globals_m.html create mode 100644 apidoc/html/globals_r.html create mode 100644 apidoc/html/globals_s.html create mode 100644 apidoc/html/globals_vars.html create mode 100644 apidoc/html/globals_x.html create mode 100644 apidoc/html/index.html create mode 100644 apidoc/html/jquery.js create mode 100644 apidoc/html/md_CHANGELOG.html create mode 100644 apidoc/html/md_CONTRIBUTING.html create mode 100644 apidoc/html/menu.js create mode 100644 apidoc/html/menudata.js create mode 100644 apidoc/html/minus.svg create mode 100644 apidoc/html/minusd.svg create mode 100644 apidoc/html/nav_f.png create mode 100644 apidoc/html/nav_fd.png create mode 100644 apidoc/html/nav_g.png create mode 100644 apidoc/html/nav_h.png create mode 100644 apidoc/html/nav_hd.png create mode 100644 apidoc/html/navtree.css create mode 100644 apidoc/html/navtree.js create mode 100644 apidoc/html/navtreedata.js create mode 100644 apidoc/html/navtreeindex0.js create mode 100644 apidoc/html/navtreeindex1.js create mode 100644 apidoc/html/open.png create mode 100644 apidoc/html/pages.html create mode 100644 apidoc/html/plugin.xml create mode 100644 apidoc/html/plus.svg create mode 100644 apidoc/html/plusd.svg create mode 100644 apidoc/html/resize.js create mode 100644 apidoc/html/search/all_0.js create mode 100644 apidoc/html/search/all_1.js create mode 100644 apidoc/html/search/all_10.js create mode 100644 apidoc/html/search/all_11.js create mode 100644 apidoc/html/search/all_12.js create mode 100644 apidoc/html/search/all_13.js create mode 100644 apidoc/html/search/all_14.js create mode 100644 apidoc/html/search/all_15.js create mode 100644 apidoc/html/search/all_16.js create mode 100644 apidoc/html/search/all_2.js create mode 100644 apidoc/html/search/all_3.js create mode 100644 apidoc/html/search/all_4.js create mode 100644 apidoc/html/search/all_5.js create mode 100644 apidoc/html/search/all_6.js create mode 100644 apidoc/html/search/all_7.js create mode 100644 apidoc/html/search/all_8.js create mode 100644 apidoc/html/search/all_9.js create mode 100644 apidoc/html/search/all_a.js create mode 100644 apidoc/html/search/all_b.js create mode 100644 apidoc/html/search/all_c.js create mode 100644 apidoc/html/search/all_d.js create mode 100644 apidoc/html/search/all_e.js create mode 100644 apidoc/html/search/all_f.js create mode 100644 apidoc/html/search/classes_0.js create mode 100644 apidoc/html/search/close.svg create mode 100644 apidoc/html/search/defines_0.js create mode 100644 apidoc/html/search/defines_1.js create mode 100644 apidoc/html/search/defines_2.js create mode 100644 apidoc/html/search/defines_3.js create mode 100644 apidoc/html/search/defines_4.js create mode 100644 apidoc/html/search/files_0.js create mode 100644 apidoc/html/search/functions_0.js create mode 100644 apidoc/html/search/functions_1.js create mode 100644 apidoc/html/search/mag.svg create mode 100644 apidoc/html/search/mag_d.svg create mode 100644 apidoc/html/search/mag_sel.svg create mode 100644 apidoc/html/search/mag_seld.svg create mode 100644 apidoc/html/search/pages_0.js create mode 100644 apidoc/html/search/pages_1.js create mode 100644 apidoc/html/search/pages_2.js create mode 100644 apidoc/html/search/pages_3.js create mode 100644 apidoc/html/search/search.css create mode 100644 apidoc/html/search/search.js create mode 100644 apidoc/html/search/searchdata.js create mode 100644 apidoc/html/search/variables_0.js create mode 100644 apidoc/html/search/variables_1.js create mode 100644 apidoc/html/search/variables_2.js create mode 100644 apidoc/html/search/variables_3.js create mode 100644 apidoc/html/search/variables_4.js create mode 100644 apidoc/html/search/variables_5.js create mode 100644 apidoc/html/search/variables_6.js create mode 100644 apidoc/html/search/variables_7.js create mode 100644 apidoc/html/search/variables_8.js create mode 100644 apidoc/html/search/variables_9.js create mode 100644 apidoc/html/search/variables_a.js create mode 100644 apidoc/html/search/variables_b.js create mode 100644 apidoc/html/smax-easy_8c.html create mode 100644 apidoc/html/smax-easy_8c.js create mode 100644 apidoc/html/smax-lazy_8c.html create mode 100644 apidoc/html/smax-lazy_8c.js create mode 100644 apidoc/html/smax-messages_8c.html create mode 100644 apidoc/html/smax-messages_8c.js create mode 100644 apidoc/html/smax-meta_8c.html create mode 100644 apidoc/html/smax-meta_8c.js create mode 100644 apidoc/html/smax-private_8h.html create mode 100644 apidoc/html/smax-private_8h.js create mode 100644 apidoc/html/smax-queue_8c.html create mode 100644 apidoc/html/smax-queue_8c.js create mode 100644 apidoc/html/smax-resilient_8c.html create mode 100644 apidoc/html/smax-resilient_8c.js create mode 100644 apidoc/html/smax-util_8c.html create mode 100644 apidoc/html/smax-util_8c.js create mode 100644 apidoc/html/smax_8c.html create mode 100644 apidoc/html/smax_8c.js create mode 100644 apidoc/html/smax_8h.html create mode 100644 apidoc/html/smax_8h.js create mode 100644 apidoc/html/smithsonian-logo-55x55.png create mode 100644 apidoc/html/splitbar.png create mode 100644 apidoc/html/splitbard.png create mode 100644 apidoc/html/structXCoordinateAxis.html create mode 100644 apidoc/html/structXCoordinateAxis.js create mode 100644 apidoc/html/structXCoordinateSystem.html create mode 100644 apidoc/html/structXCoordinateSystem.js create mode 100644 apidoc/html/structXMessage.html create mode 100644 apidoc/html/structXMessage.js create mode 100644 apidoc/html/structXMeta.html create mode 100644 apidoc/html/structXMeta.js create mode 100644 apidoc/html/structXSyncPoint.html create mode 100644 apidoc/html/structXSyncPoint.js create mode 100644 apidoc/html/sync_off.png create mode 100644 apidoc/html/sync_on.png create mode 100644 apidoc/html/tab_a.png create mode 100644 apidoc/html/tab_ad.png create mode 100644 apidoc/html/tab_b.png create mode 100644 apidoc/html/tab_bd.png create mode 100644 apidoc/html/tab_h.png create mode 100644 apidoc/html/tab_hd.png create mode 100644 apidoc/html/tab_s.png create mode 100644 apidoc/html/tab_sd.png create mode 100644 apidoc/html/tabs.css create mode 100644 apidoc/html/toc.xml create mode 100644 apidoc/man/man3/XCoordinateAxis.3 create mode 100644 apidoc/man/man3/XCoordinateSystem.3 create mode 100644 apidoc/man/man3/XMessage.3 create mode 100644 apidoc/man/man3/XMeta.3 create mode 100644 apidoc/man/man3/XSyncPoint.3 create mode 100644 apidoc/man/man3/md_CHANGELOG.3 create mode 100644 apidoc/man/man3/md_CONTRIBUTING.3 create mode 100644 apidoc/man/man3/smax-easy.c.3 create mode 100644 apidoc/man/man3/smax-lazy.c.3 create mode 100644 apidoc/man/man3/smax-messages.c.3 create mode 100644 apidoc/man/man3/smax-meta.c.3 create mode 100644 apidoc/man/man3/smax-private.h.3 create mode 100644 apidoc/man/man3/smax-queue.c.3 create mode 100644 apidoc/man/man3/smax-resilient.c.3 create mode 100644 apidoc/man/man3/smax-util.c.3 create mode 100644 apidoc/man/man3/smax.c.3 create mode 100644 apidoc/man/man3/smax.h.3 create mode 100644 apidoc/smax.tag create mode 100644 doc/CHANGELOG.md create mode 100644 doc/README.md create mode 120000 doc/resources create mode 100644 favicon.ico create mode 100644 index.md create mode 100644 resources/CHANGELOG.md create mode 100644 resources/CfA-logo.png create mode 100644 resources/README.md create mode 100644 resources/android-chrome-192x192.png create mode 100644 resources/android-chrome-512x512.png create mode 100644 resources/apple-touch-icon.png create mode 100644 resources/favicon-16x16.png create mode 100644 resources/favicon-32x32.png create mode 100644 resources/favicon.ico create mode 100644 resources/smithsonian-logo.png diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..cdb81f7 --- /dev/null +++ b/Gemfile @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +source "https://rubygems.org" +gem 'jekyll-sitemap' +gem 'jekyll-titles-from-headings' + +# gem "rails" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fdddb29 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..ab5a474 --- /dev/null +++ b/_config.yml @@ -0,0 +1,27 @@ +theme: jekyll-theme-Tactile +author: Attila Kovacs +github_username: attipaci +title: smax-clib +description: C/C++ client library for SMA-X structured data exchange +show_downloads: false +#google_analytics: G-2L0MEN3Z8Q +url: "https://smithsonian.github.io" +read_time: true +titles_from_headings: + strip_title: true +plugins: + - jekyll-sitemap + - jekyll-titles-from-headings + - jekyll-toc +defaults: + # Exclude search pages from sitemap + - scope: + path: apidoc/html/search/** + values: + sitemap: false + # Exclude google site verification from sitemap + - scope: + path: google*.html + values: + sitemap: false + diff --git a/_includes/head-custom-google-analytics.html b/_includes/head-custom-google-analytics.html new file mode 100644 index 0000000..dc0271e --- /dev/null +++ b/_includes/head-custom-google-analytics.html @@ -0,0 +1,11 @@ + +{% if site.google_analytics %} + + +{% endif %} diff --git a/_includes/head-custom.html b/_includes/head-custom.html new file mode 100644 index 0000000..6cc051c --- /dev/null +++ b/_includes/head-custom.html @@ -0,0 +1,16 @@ + + + + + + + +{% include head-custom-google-analytics.html %} + + + + + + + + diff --git a/_includes/site.webmanifest b/_includes/site.webmanifest new file mode 100644 index 0000000..0b3cbfa --- /dev/null +++ b/_includes/site.webmanifest @@ -0,0 +1 @@ +{"name":"","short_name":"","icons":[{"src":"/smax-clib/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/smax-clib/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} diff --git a/_sass/jekyll-theme-tactile.scss b/_sass/jekyll-theme-tactile.scss new file mode 100644 index 0000000..ac0d3ad --- /dev/null +++ b/_sass/jekyll-theme-tactile.scss @@ -0,0 +1,383 @@ +@import "rouge-base16-dark"; +@import url('https://fonts.googleapis.com/css?family=Chivo:900'); + +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + padding: 0; + margin: 0; + font: inherit; + font-size: 100%; + vertical-align: baseline; + border: 0; +} +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-spacing: 0; + border-collapse: collapse; +} + +/* LAYOUT STYLES */ +body { + font-family: 'Helvetica Neue', Helvetica, Arial, serif; + font-size: 1em; + line-height: 1.5; + color: #6d6d6d; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8); + background: #e7e7e7 url(../images/body-bg.png) 0 0 repeat; +} + +a { + color: #8d0034; +} +a:hover { + color: #8D6088; +} + +header { + padding-top: 35px; + padding-bottom: 25px; +} + +header h1 { + font-family: 'Chivo', 'Helvetica Neue', Helvetica, Arial, serif; + font-size: 48px; font-weight: 900; + line-height: 1.2; + color: #303030; + letter-spacing: -1px; +} + +header h2 { + font-size: 24px; + font-weight: normal; + line-height: 1.3; + color: #aaa; + letter-spacing: -1px; +} + +#container { + min-height: 595px; + background: transparent url(../images/highlight-bg.jpg) 50% 0 no-repeat; +} + +.inner { + width: 620px; + margin: 0 auto; +} + +#container .inner img { + max-width: 100%; +} + +#downloads { + margin-bottom: 40px; +} + +a.button { + display: block; + float: left; + width: 179px; + padding: 12px 8px 12px 8px; + margin-right: 14px; + font-size: 15px; + font-weight: bold; + line-height: 25px; + color: #303030; + background: #fdfdfd; /* Old browsers */ + background: -moz-linear-gradient(top, #fdfdfd 0%, #f2f2f2 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#fdfdfd), color-stop(100%,#f2f2f2)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #fdfdfd 0%,#f2f2f2 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, #fdfdfd 0%,#f2f2f2 100%); /* Opera 11.10+ */ + background: -ms-linear-gradient(top, #fdfdfd 0%,#f2f2f2 100%); /* IE10+ */ + background: linear-gradient(to top, #fdfdfd 0%,#f2f2f2 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fdfdfd', endColorstr='#f2f2f2',GradientType=0 ); /* IE6-9 */ + border-top: solid 1px #cbcbcb; + border-right: solid 1px #b7b7b7; + border-bottom: solid 1px #b3b3b3; + border-left: solid 1px #b7b7b7; + border-radius: 30px; + -webkit-box-shadow: 10px 10px 5px #888; + -moz-box-shadow: 10px 10px 5px #888; + box-shadow: 0px 1px 5px #e8e8e8; + -moz-border-radius: 30px; + -webkit-border-radius: 30px; +} +a.button:hover { + background: #fafafa; /* Old browsers */ + background: -moz-linear-gradient(top, #fdfdfd 0%, #f6f6f6 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#fdfdfd), color-stop(100%,#f6f6f6)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #fdfdfd 0%,#f6f6f6 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, #fdfdfd 0%,#f6f6f6 100%); /* Opera 11.10+ */ + background: -ms-linear-gradient(top, #fdfdfd 0%,#f6f6f6 100%); /* IE10+ */ + background: linear-gradient(to top, #fdfdfd 0%,#f6f6f6, 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fdfdfd', endColorstr='#f6f6f6',GradientType=0 ); /* IE6-9 */ + border-top: solid 1px #b7b7b7; + border-right: solid 1px #b3b3b3; + border-bottom: solid 1px #b3b3b3; + border-left: solid 1px #b3b3b3; +} + +a.button span { + display: block; + height: 23px; + padding-left: 50px; +} + +#download-zip span { + background: transparent url(../images/zip-icon.png) 12px 50% no-repeat; +} +#download-tar-gz span { + background: transparent url(../images/tar-gz-icon.png) 12px 50% no-repeat; +} +#view-on-github span { + background: transparent url(../images/octocat-icon.png) 12px 50% no-repeat; +} +#view-on-github { + margin-right: 0; +} + +code, pre { + margin-bottom: 30px; + font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; + font-size: 14px; + color: #222; +} + +code { + padding: 0 3px; + background-color: #f2f2f2; + border: solid 1px #ddd; +} + +pre { + padding: 20px; + overflow: auto; + color: #f2f2f2; + text-shadow: none; + background: #303030; +} +pre code { + padding: 0; + color: #f2f2f2; + background-color: #303030; + border: none; +} + +ul, ol, dl { + margin-bottom: 20px; +} + + +/* COMMON STYLES */ + +hr { + height: 1px; + padding-bottom: 1em; + margin-top: 1em; + line-height: 1px; + background: transparent url('../images/hr.png') 50% 0 no-repeat; + border: none; +} + +strong { + font-weight: bold; +} + +em { + font-style: italic; +} + +table { + width: 100%; + border: 1px solid #ebebeb; +} + +th { + font-weight: 500; +} + +td { + font-weight: 300; + text-align: center; + border: 1px solid #ebebeb; +} + +form { + padding: 20px; + background: #f2f2f2; + +} + + +/* GENERAL ELEMENT TYPE STYLES */ + +h1 { + font-size: 32px; +} + +h2 { + margin-bottom: 8px; + font-size: 22px; + font-weight: bold; + color: #303030; +} + +h3 { + margin-bottom: 8px; + font-size: 18px; + font-weight: bold; + color: #8d0034; +} + +h4 { + font-size: 16px; + font-weight: bold; + color: #303030; +} + +h5 { + font-size: 1em; + color: #303030; +} + +h6 { + font-size: .8em; + color: #303030; +} + +p { + margin-bottom: 20px; + font-weight: 300; +} + +a { + text-decoration: none; +} + +p a { + font-weight: 400; +} + +blockquote { + padding: 0 0 0 30px; + margin-bottom: 20px; + font-size: 1.6em; + border-left: 10px solid #e9e9e9; +} + +ul li { + list-style-position: inside; + list-style: disc; + padding-left: 20px; +} + +ol li { + list-style-position: inside; + list-style: decimal; + padding-left: 3px; +} + +dl dt { + color: #303030; +} + +footer { + padding-top: 20px; + padding-bottom: 30px; + margin-top: 40px; + font-size: 13px; + color: #aaa; + background: transparent url('../images/hr.png') 0 0 no-repeat; +} + +footer a { + color: #666; +} +footer a:hover { + color: #444; +} + +/* MISC */ +.clearfix:after { + display: block; + height: 0; + clear: both; + visibility: hidden; + content: '.'; +} + +.clearfix {display: inline-block;} +* html .clearfix {height: 1%;} +.clearfix {display: block;} + +/* #Media Queries +================================================== */ + +/* Smaller than standard 960 (devices and browsers) */ +@media only screen and (max-width: 959px) { } + +/* Tablet Portrait size to standard 960 (devices and browsers) */ +@media only screen and (min-width: 768px) and (max-width: 959px) { } + +/* All Mobile Sizes (devices and browser) */ +@media only screen and (max-width: 767px) { + header { + padding-top: 10px; + padding-bottom: 10px; + } + #downloads { + margin-bottom: 25px; + } + #download-zip, #download-tar-gz { + display: none; + } + .inner { + width: 94%; + margin: 0 auto; + } + ul li { + margin-left: 10px; + padding-left: 10px; + } + ol li { + margin-left: 10px; + } +} + +/* Mobile Landscape Size to Tablet Portrait (devices and browsers) */ +@media only screen and (min-width: 480px) and (max-width: 767px) { } + +/* Mobile Portrait Size to Mobile Landscape Size (devices and browsers) */ +@media only screen and (max-width: 479px) { } diff --git a/apidoc/html/annotated.html b/apidoc/html/annotated.html new file mode 100644 index 0000000..c304a08 --- /dev/null +++ b/apidoc/html/annotated.html @@ -0,0 +1,119 @@ + + + + + + + +smax-clib: Data Structures + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
Data Structures
+
+
+
Here are the data structures with brief descriptions:
+ + + + + + +
 CXCoordinateAxisStructure that defines a coordinate axis in an XCoordinateSystem for an SMA-X data array
 CXCoordinateSystemStructure that defines a coordinate system, with one or more XCoordinateAxis
 CXMessageSMA-X program message
 CXMetaSMA-X standard metadata
 CXSyncPointSynchronization point that can be waited upon when queueing pipelined pulls
+
+
+
+ + + + diff --git a/apidoc/html/annotated_dup.js b/apidoc/html/annotated_dup.js new file mode 100644 index 0000000..683a081 --- /dev/null +++ b/apidoc/html/annotated_dup.js @@ -0,0 +1,8 @@ +var annotated_dup = +[ + [ "XCoordinateAxis", "structXCoordinateAxis.html", "structXCoordinateAxis" ], + [ "XCoordinateSystem", "structXCoordinateSystem.html", "structXCoordinateSystem" ], + [ "XMessage", "structXMessage.html", "structXMessage" ], + [ "XMeta", "structXMeta.html", "structXMeta" ], + [ "XSyncPoint", "structXSyncPoint.html", "structXSyncPoint" ] +]; \ No newline at end of file diff --git a/apidoc/html/bc_s.png b/apidoc/html/bc_s.png new file mode 100644 index 0000000000000000000000000000000000000000..21d5d360bc8cc604ee535cfec7e73467038b7db4 GIT binary patch literal 633 zcmV-<0*3vGP)4qAvkO{Oj)GsbO2k=B1X0hur1;w3@N!;lh-vGji^*A#p!f~_nTBI)l&d( zRsr#!e>t1Ya(27@F=7s2tyW9&D#qA27z_#ug(7}-cJ^fnG@H#uTtS9gMx*f*z>_7= zXfzh_6+sZb1_FUUh`qgD?_36UcXwAmdE|DxLt3qNAHWM4sMqVOKpf&BpbG$U_tpVv zeL_zRq9~^N{r+24tJR2zvmF%r$ZEBY0Ni2KYL$pM)8eS#kp)h1gHATSPyGbc+sR%-8OX$O$?FVq{LX?4lQQW)oOB4nM1l{O2a3g|K z6c=I}w6vqR8^|n0!T+6^)Fj^_+#mOx)BnB6d2}x}n@#HVdZZ`{34%cJc-#i5s%lIo z6JtJ~$5d4%C;a4byWL*SX0szeilW$HwOZ{K5xp)H3co!bPjR(c{e{1OxPb5PBuNS- z5{W14_4E`Y)(dDtz~V9c~bD(*S}mdqKHeHtlDkC{ByT z;(OSSbX~uSB4CmN7yW+Um`MmL$vaE))vUX0s_%I2?9z&}y|l zb-Ue{+$UL-GAHB}O8OahaRf>s{c4wB2r>^6A + + + + + + +smax-clib: Data Structure Index + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
Data Structure Index
+
+ +
+ + + + diff --git a/apidoc/html/clipboard.js b/apidoc/html/clipboard.js new file mode 100644 index 0000000..42c1fb0 --- /dev/null +++ b/apidoc/html/clipboard.js @@ -0,0 +1,61 @@ +/** + +The code below is based on the Doxygen Awesome project, see +https://github.com/jothepro/doxygen-awesome-css + +MIT License + +Copyright (c) 2021 - 2022 jothepro + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +let clipboard_title = "Copy to clipboard" +let clipboard_icon = `` +let clipboard_successIcon = `` +let clipboard_successDuration = 1000 + +$(function() { + if(navigator.clipboard) { + const fragments = document.getElementsByClassName("fragment") + for(const fragment of fragments) { + const clipboard_div = document.createElement("div") + clipboard_div.classList.add("clipboard") + clipboard_div.innerHTML = clipboard_icon + clipboard_div.title = clipboard_title + $(clipboard_div).click(function() { + const content = this.parentNode.cloneNode(true) + // filter out line number and folded fragments from file listings + content.querySelectorAll(".lineno, .ttc, .foldclosed").forEach((node) => { node.remove() }) + let text = content.textContent + // remove trailing newlines and trailing spaces from empty lines + text = text.replace(/^\s*\n/gm,'\n').replace(/\n*$/,'') + navigator.clipboard.writeText(text); + this.classList.add("success") + this.innerHTML = clipboard_successIcon + window.setTimeout(() => { // switch back to normal icon after timeout + this.classList.remove("success") + this.innerHTML = clipboard_icon + }, clipboard_successDuration); + }) + fragment.insertBefore(clipboard_div, fragment.firstChild) + } + } +}) diff --git a/apidoc/html/closed.png b/apidoc/html/closed.png new file mode 100644 index 0000000000000000000000000000000000000000..11c68adbe13453953a68e07b63ff011b8ab4f1de GIT binary patch literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>1|%O$WD@{VE}kxqAr*{o=U(JwP~dQh?|Y-L zE=GbyD^*ygJl^iB8-s`8W=<7u2VYk92{MeKcR#;gy6Zw*mbL58(_+8MtPTiwHDois XuoU5soVLvyXdZ*7tDnm{r-UW|b#f$x literal 0 HcmV?d00001 diff --git a/apidoc/html/cookie.js b/apidoc/html/cookie.js new file mode 100644 index 0000000..53ad21d --- /dev/null +++ b/apidoc/html/cookie.js @@ -0,0 +1,58 @@ +/*! + Cookie helper functions + Copyright (c) 2023 Dimitri van Heesch + Released under MIT license. +*/ +let Cookie = { + cookie_namespace: 'doxygen_', + + readSetting(cookie,defVal) { + if (window.chrome) { + const val = localStorage.getItem(this.cookie_namespace+cookie) || + sessionStorage.getItem(this.cookie_namespace+cookie); + if (val) return val; + } else { + let myCookie = this.cookie_namespace+cookie+"="; + if (document.cookie) { + const index = document.cookie.indexOf(myCookie); + if (index != -1) { + const valStart = index + myCookie.length; + let valEnd = document.cookie.indexOf(";", valStart); + if (valEnd == -1) { + valEnd = document.cookie.length; + } + return document.cookie.substring(valStart, valEnd); + } + } + } + return defVal; + }, + + writeSetting(cookie,val,days=10*365) { // default days='forever', 0=session cookie, -1=delete + if (window.chrome) { + if (days==0) { + sessionStorage.setItem(this.cookie_namespace+cookie,val); + } else { + localStorage.setItem(this.cookie_namespace+cookie,val); + } + } else { + let date = new Date(); + date.setTime(date.getTime()+(days*24*60*60*1000)); + const expiration = days!=0 ? "expires="+date.toGMTString()+";" : ""; + document.cookie = this.cookie_namespace + cookie + "=" + + val + "; SameSite=Lax;" + expiration + "path=/"; + } + }, + + eraseSetting(cookie) { + if (window.chrome) { + if (localStorage.getItem(this.cookie_namespace+cookie)) { + localStorage.removeItem(this.cookie_namespace+cookie); + } else if (sessionStorage.getItem(this.cookie_namespace+cookie)) { + sessionStorage.removeItem(this.cookie_namespace+cookie); + } + } else { + this.writeSetting(cookie,'',-1); + } + }, +} diff --git a/apidoc/html/darkmode_toggle.js b/apidoc/html/darkmode_toggle.js new file mode 100644 index 0000000..b9c7364 --- /dev/null +++ b/apidoc/html/darkmode_toggle.js @@ -0,0 +1,222 @@ +/** + +The code below is based on the Doxygen Awesome project with some minor modifications +https://github.com/jothepro/doxygen-awesome-css + +MIT License + +Copyright (c) 2021 - 2022 jothepro + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +class DarkModeToggle extends HTMLElement { + + static darkmode_cookie_name = ''+'prefers-dark'; + static lightmode_cookie_name = ''+'prefers-light'; + + static icon = ''; + static title = "Toggle Light/Dark Mode" + + static prefersLightModeInDarkModeKey = "prefers-light-mode-in-dark-mode" + static prefersDarkModeInLightModeKey = "prefers-dark-mode-in-light-mode" + + static _staticConstructor = function() { + DarkModeToggle.enableDarkMode(DarkModeToggle.userPreference) + // Update the color scheme when the browsers preference changes + // without user interaction on the website. + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => { + DarkModeToggle.onSystemPreferenceChanged() + }) + // Update the color scheme when the tab is made visible again. + // It is possible that the appearance was changed in another tab + // while this tab was in the background. + document.addEventListener("visibilitychange", visibilityState => { + if (document.visibilityState === 'visible') { + DarkModeToggle.onSystemPreferenceChanged() + } + }); + }() + + static init() { + $(function() { + $(document).ready(function() { + const toggleButton = document.createElement('dark-mode-toggle') + toggleButton.title = DarkModeToggle.title + toggleButton.innerHTML = DarkModeToggle.icon + toggleButton.tabIndex = 0; + + function addButton() { + const titleArea = document.getElementById("titlearea"); + const searchBox = document.getElementById("MSearchBox"); + const mainMenu = document.getElementById("main-menu"); + const navRow1 = document.getElementById("navrow1"); + let mainMenuVisible = false; + if (mainMenu) { + const menuStyle = window.getComputedStyle(mainMenu); + mainMenuVisible = menuStyle.display!=='none' + } + const searchBoxPos1 = document.getElementById("searchBoxPos1"); + if (searchBox) { // (1) search box visible + searchBox.parentNode.appendChild(toggleButton) + } else if (navRow1) { // (2) no search box, static menu bar + const li = document.createElement('li'); + li.style = 'float: right;' + li.appendChild(toggleButton); + toggleButton.style = 'width: 24px; height: 25px; padding-top: 11px; float: right;'; + const row = document.querySelector('#navrow1 > ul:first-of-type'); + row.appendChild(li) + } else if (mainMenu && mainMenuVisible) { // (3) no search box + dynamic menu bar expanded + const li = document.createElement('li'); + li.style = 'float: right;' + li.appendChild(toggleButton); + toggleButton.style = 'width: 14px; height: 36px; padding-top: 10px; float: right;'; + mainMenu.appendChild(li) + } else if (searchBoxPos1) { // (4) no search box + dynamic menu bar collapsed + toggleButton.style = 'width: 24px; height: 36px; padding-top: 10px; float: right;'; + searchBoxPos1.style = 'top: 0px;' + searchBoxPos1.appendChild(toggleButton); + } else if (titleArea) { // (5) no search box and no navigation tabs + toggleButton.style = 'width: 24px; height: 24px; position: absolute; right: 0px; top: 34px;'; + titleArea.append(toggleButton); + } + } + + $(document).ready(() => addButton()); + $(window).resize(() => addButton()); + let inFocus = false; + $(document).focusin(() => inFocus = true); + $(document).focusout(() => inFocus = false); + $(document).keyup(function(e) { + if (e.keyCode==27 && !inFocus) { // escape key maps to keycode `27` + e.stopPropagation(); + DarkModeToggle.userPreference = !DarkModeToggle.userPreference + } + }) + DarkModeToggle.setDarkModeVisibility(DarkModeToggle.darkModeEnabled) + }) + }) + } + + constructor() { + super(); + this.onclick=this.toggleDarkMode + this.onkeypress=function(e){if (e.keyCode==13) { this.toggleDarkMode(); }}; + } + + /** + * @returns `true` for dark-mode, `false` for light-mode system preference + */ + static get systemPreference() { + return window.matchMedia('(prefers-color-scheme: dark)').matches + } + + static get prefersDarkModeInLightMode() { + return Cookie.readSetting(DarkModeToggle.darkmode_cookie_name,'0')=='1'; + } + + static set prefersDarkModeInLightMode(preference) { + if (preference) { + Cookie.writeSetting(DarkModeToggle.darkmode_cookie_name,'1'); + } else { + Cookie.eraseSetting(DarkModeToggle.darkmode_cookie_name); + } + } + + static get prefersLightModeInDarkMode() { + return Cookie.readSetting(DarkModeToggle.lightmode_cookie_name,'0')=='1' + } + + static set prefersLightModeInDarkMode(preference) { + if (preference) { + Cookie.writeSetting(DarkModeToggle.lightmode_cookie_name,'1'); + } else { + Cookie.eraseSetting(DarkModeToggle.lightmode_cookie_name); + } + } + + /** + * @returns `true` for dark-mode, `false` for light-mode user preference + */ + static get userPreference() { + return (!DarkModeToggle.systemPreference && DarkModeToggle.prefersDarkModeInLightMode) || + (DarkModeToggle.systemPreference && !DarkModeToggle.prefersLightModeInDarkMode) + } + + static set userPreference(userPreference) { + DarkModeToggle.darkModeEnabled = userPreference + if (!userPreference) { + if (DarkModeToggle.systemPreference) { + DarkModeToggle.prefersLightModeInDarkMode = true + } else { + DarkModeToggle.prefersDarkModeInLightMode = false + } + } else { + if (!DarkModeToggle.systemPreference) { + DarkModeToggle.prefersDarkModeInLightMode = true + } else { + DarkModeToggle.prefersLightModeInDarkMode = false + } + } + DarkModeToggle.onUserPreferenceChanged() + } + + static setDarkModeVisibility(enable) { + let darkModeStyle, lightModeStyle; + if(enable) { + darkModeStyle = 'inline-block'; + lightModeStyle = 'none' + } else { + darkModeStyle = 'none'; + lightModeStyle = 'inline-block' + } + document.querySelectorAll('.dark-mode-visible' ).forEach(el => el.style.display = darkModeStyle); + document.querySelectorAll('.light-mode-visible').forEach(el => el.style.display = lightModeStyle); + } + static enableDarkMode(enable) { + if(enable) { + DarkModeToggle.darkModeEnabled = true + document.documentElement.classList.add("dark-mode") + document.documentElement.classList.remove("light-mode") + } else { + DarkModeToggle.darkModeEnabled = false + document.documentElement.classList.remove("dark-mode") + document.documentElement.classList.add("light-mode") + } + DarkModeToggle.setDarkModeVisibility(enable) + } + + static onSystemPreferenceChanged() { + DarkModeToggle.darkModeEnabled = DarkModeToggle.userPreference + DarkModeToggle.enableDarkMode(DarkModeToggle.darkModeEnabled) + } + + static onUserPreferenceChanged() { + DarkModeToggle.enableDarkMode(DarkModeToggle.darkModeEnabled) + } + + toggleDarkMode() { + DarkModeToggle.userPreference = !DarkModeToggle.userPreference + } +} + +customElements.define("dark-mode-toggle", DarkModeToggle); + +DarkModeToggle.init(); diff --git a/apidoc/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html b/apidoc/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html new file mode 100644 index 0000000..124dcf1 --- /dev/null +++ b/apidoc/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html @@ -0,0 +1,139 @@ + + + + + + + +smax-clib: src Directory Reference + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
src Directory Reference
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+Files

 smax-easy.c
 A set of functions for simplified access to SMA-X for specific variable types.
 
 smax-lazy.c
 A set of functions to support the efficient retrieval of lazy variables, that is variables that change infrequently, from the SMA-X database. Rather than querying the database on every call, the first lazy pull of a variable initiates monitoring for updates. The pull requests will return the current state of the variable at all times, but it generates minimal network traffic only when the underlying value in the database is changed.
 
 smax-messages.c
 Simple API for sending and receiving program broadcast messages through SMA-X.
 
 smax-meta.c
 A set of utility functions for manipulating optional static metadata.
 
 smax-queue.c
 Functions to support pipelined pull requests from SMA-X. Because they don't requite a sequence of round-trips, pipelined pulls can be orders of magnitude faster than staggered regular pull requests.
 
 smax-resilient.c
 This module adds trusty push delivery to SMA-X. If the server cannot be reached, push requests are stored and updated locally until the server connection is restored, at which point they are delivered.
 
 smax-util.c
 A collection of commonly used functions for the SMA-X library.
 
 smax.c
 SMA-X is a software implementation for SMA shared data, and is the base layer for the software reflective memory (RM) emulation, and DSM replacement. It works by communicating TCP/IP messages to a central Redis server.
 
+
+
+ + + + diff --git a/apidoc/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js b/apidoc/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js new file mode 100644 index 0000000..5fed6a0 --- /dev/null +++ b/apidoc/html/dir_68267d1309a1af8e8297ef4c3efbcdba.js @@ -0,0 +1,11 @@ +var dir_68267d1309a1af8e8297ef4c3efbcdba = +[ + [ "smax-easy.c", "smax-easy_8c.html", "smax-easy_8c" ], + [ "smax-lazy.c", "smax-lazy_8c.html", "smax-lazy_8c" ], + [ "smax-messages.c", "smax-messages_8c.html", "smax-messages_8c" ], + [ "smax-meta.c", "smax-meta_8c.html", "smax-meta_8c" ], + [ "smax-queue.c", "smax-queue_8c.html", "smax-queue_8c" ], + [ "smax-resilient.c", "smax-resilient_8c.html", "smax-resilient_8c" ], + [ "smax-util.c", "smax-util_8c.html", "smax-util_8c" ], + [ "smax.c", "smax_8c.html", "smax_8c" ] +]; \ No newline at end of file diff --git a/apidoc/html/dir_d44c64559bbebec7f509842c48db8b23.html b/apidoc/html/dir_d44c64559bbebec7f509842c48db8b23.html new file mode 100644 index 0000000..f5af382 --- /dev/null +++ b/apidoc/html/dir_d44c64559bbebec7f509842c48db8b23.html @@ -0,0 +1,120 @@ + + + + + + + +smax-clib: include Directory Reference + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
include Directory Reference
+
+
+ + + + + + + +

+Files

 smax-private.h
 A set of private SMA-X routines used by the API library but should not be exposed outside.
 
 smax.h
 
+
+
+ + + + diff --git a/apidoc/html/dir_d44c64559bbebec7f509842c48db8b23.js b/apidoc/html/dir_d44c64559bbebec7f509842c48db8b23.js new file mode 100644 index 0000000..3842b24 --- /dev/null +++ b/apidoc/html/dir_d44c64559bbebec7f509842c48db8b23.js @@ -0,0 +1,5 @@ +var dir_d44c64559bbebec7f509842c48db8b23 = +[ + [ "smax-private.h", "smax-private_8h.html", "smax-private_8h" ], + [ "smax.h", "smax_8h.html", "smax_8h" ] +]; \ No newline at end of file diff --git a/apidoc/html/doc.svg b/apidoc/html/doc.svg new file mode 100644 index 0000000..959997b --- /dev/null +++ b/apidoc/html/doc.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/apidoc/html/docd.svg b/apidoc/html/docd.svg new file mode 100644 index 0000000..210b464 --- /dev/null +++ b/apidoc/html/docd.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/apidoc/html/doxygen.css b/apidoc/html/doxygen.css new file mode 100644 index 0000000..08351a5 --- /dev/null +++ b/apidoc/html/doxygen.css @@ -0,0 +1,2205 @@ +/* The standard CSS for doxygen 1.10.0*/ + +html { +/* page base colors */ +--page-background-color: white; +--page-foreground-color: black; +--page-link-color: #505050; +--page-visited-link-color: #606060; + +/* index */ +--index-odd-item-bg-color: #F9F9F9; +--index-even-item-bg-color: white; +--index-header-color: black; +--index-separator-color: #A0A0A0; + +/* header */ +--header-background-color: #FAFAFA; +--header-separator-color: #CCCCCC; +--header-gradient-image: url('nav_h.png'); +--group-header-separator-color: #999999; +--group-header-color: #444444; +--inherit-header-color: gray; + +--footer-foreground-color: #333333; +--footer-logo-width: 104px; +--citation-label-color: #404040; +--glow-color: cyan; + +--title-background-color: white; +--title-separator-color: #707070; +--directory-separator-color: #AAAAAA; +--separator-color: #666666; + +--blockquote-background-color: #F8F8F8; +--blockquote-border-color: #AAAAAA; + +--scrollbar-thumb-color: #AAAAAA; +--scrollbar-background-color: #FAFAFA; + +--icon-background-color: #888888; +--icon-foreground-color: white; +--icon-doc-image: url('doc.svg'); +--icon-folder-open-image: url('folderopen.svg'); +--icon-folder-closed-image: url('folderclosed.svg'); + +/* brief member declaration list */ +--memdecl-background-color: #FAFAFA; +--memdecl-separator-color: #E2E2E2; +--memdecl-foreground-color: #555; +--memdecl-template-color: #606060; + +/* detailed member list */ +--memdef-border-color: #B4B4B4; +--memdef-title-background-color: #E6E6E6; +--memdef-title-gradient-image: url('nav_f.png'); +--memdef-proto-background-color: #E3E3E3; +--memdef-proto-text-color: #2B2B2B; +--memdef-proto-text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); +--memdef-doc-background-color: white; +--memdef-param-name-color: #602020; +--memdef-template-color: #606060; + +/* tables */ +--table-cell-border-color: #373737; +--table-header-background-color: #474747; +--table-header-foreground-color: #FFFFFF; + +/* labels */ +--label-background-color: #888888; +--label-left-top-border-color: #707070; +--label-right-bottom-border-color: #CCCCCC; +--label-foreground-color: white; + +/** navigation bar/tree/menu */ +--nav-background-color: #FAFAFA; +--nav-foreground-color: #454545; +--nav-gradient-image: url('tab_b.png'); +--nav-gradient-hover-image: url('tab_h.png'); +--nav-gradient-active-image: url('tab_a.png'); +--nav-gradient-active-image-parent: url("../tab_a.png"); +--nav-separator-image: url('tab_s.png'); +--nav-breadcrumb-image: url('bc_s.png'); +--nav-breadcrumb-border-color: #CACACA; +--nav-splitbar-image: url('splitbar.png'); +--nav-font-size-level1: 13px; +--nav-font-size-level2: 10px; +--nav-font-size-level3: 9px; +--nav-text-normal-color: #303030; +--nav-text-hover-color: white; +--nav-text-active-color: white; +--nav-text-normal-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); +--nav-text-hover-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); +--nav-text-active-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); +--nav-menu-button-color: #454545; +--nav-menu-background-color: white; +--nav-menu-foreground-color: #555555; +--nav-menu-toggle-color: rgba(255, 255, 255, 0.5); +--nav-arrow-color: #AAAAAA; +--nav-arrow-selected-color: #AAAAAA; + +/* table of contents */ +--toc-background-color: #F6F6F6; +--toc-border-color: #DDDDDD; +--toc-header-color: #606060; +--toc-down-arrow-image: url("data:image/svg+xml;utf8,&%238595;"); + +/** search field */ +--search-background-color: white; +--search-foreground-color: #909090; +--search-magnification-image: url('mag.svg'); +--search-magnification-select-image: url('mag_sel.svg'); +--search-active-color: black; +--search-filter-background-color: #FAFAFA; +--search-filter-foreground-color: black; +--search-filter-border-color: #A0A0A0; +--search-filter-highlight-text-color: white; +--search-filter-highlight-bg-color: #505050; +--search-results-foreground-color: #585858; +--search-results-background-color: #F0F0F0; +--search-results-border-color: black; +--search-box-shadow: inset 0.5px 0.5px 3px 0px #555; + +/** code fragments */ +--code-keyword-color: #008000; +--code-type-keyword-color: #604020; +--code-flow-keyword-color: #E08000; +--code-comment-color: #800000; +--code-preprocessor-color: #806020; +--code-string-literal-color: #002080; +--code-char-literal-color: #008080; +--code-xml-cdata-color: black; +--code-vhdl-digit-color: #FF00FF; +--code-vhdl-char-color: #000000; +--code-vhdl-keyword-color: #700070; +--code-vhdl-logic-color: #FF0000; +--code-link-color: #606060; +--code-external-link-color: #606060; +--fragment-foreground-color: black; +--fragment-background-color: #FCFCFC; +--fragment-border-color: #CCCCCC; +--fragment-lineno-border-color: #00FF00; +--fragment-lineno-background-color: #E8E8E8; +--fragment-lineno-foreground-color: black; +--fragment-lineno-link-fg-color: #606060; +--fragment-lineno-link-bg-color: #D8D8D8; +--fragment-lineno-link-hover-fg-color: #606060; +--fragment-lineno-link-hover-bg-color: #C8C8C8; +--fragment-copy-ok-color: #2EC82E; +--tooltip-foreground-color: black; +--tooltip-background-color: white; +--tooltip-border-color: gray; +--tooltip-doc-color: grey; +--tooltip-declaration-color: #006318; +--tooltip-link-color: #606060; +--tooltip-shadow: 1px 1px 7px gray; +--fold-line-color: #808080; +--fold-minus-image: url('minus.svg'); +--fold-plus-image: url('plus.svg'); +--fold-minus-image-relpath: url('../../minus.svg'); +--fold-plus-image-relpath: url('../../plus.svg'); + +/** font-family */ +--font-family-normal: Roboto,sans-serif; +--font-family-monospace: 'JetBrains Mono',Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace,fixed; +--font-family-nav: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; +--font-family-title: Tahoma,Arial,sans-serif; +--font-family-toc: Verdana,'DejaVu Sans',Geneva,sans-serif; +--font-family-search: Arial,Verdana,sans-serif; +--font-family-icon: Arial,Helvetica; +--font-family-tooltip: Roboto,sans-serif; + +/** special sections */ +--warning-color-bg: #f8d1cc; +--warning-color-hl: #b61825; +--warning-color-text: #75070f; +--note-color-bg: #faf3d8; +--note-color-hl: #f3a600; +--note-color-text: #5f4204; +--todo-color-bg: #e4f3ff; +--todo-color-hl: #1879C4; +--todo-color-text: #274a5c; +--test-color-bg: #e8e8ff; +--test-color-hl: #3939C4; +--test-color-text: #1a1a5c; +--deprecated-color-bg: #ecf0f3; +--deprecated-color-hl: #5b6269; +--deprecated-color-text: #43454a; +--bug-color-bg: #e4dafd; +--bug-color-hl: #5b2bdd; +--bug-color-text: #2a0d72; +--invariant-color-bg: #d8f1e3; +--invariant-color-hl: #44b86f; +--invariant-color-text: #265532; +} + +html.dark-mode { +/* page base colors */ +--page-background-color: black; +--page-foreground-color: #C9D1D9; +--page-link-color: #A0A0A0; +--page-visited-link-color: #B0B0B0; + +/* index */ +--index-odd-item-bg-color: #0A0A0A; +--index-even-item-bg-color: black; +--index-header-color: #CCCCCC; +--index-separator-color: #404040; + +/* header */ +--header-background-color: #060606; +--header-separator-color: #141414; +--header-gradient-image: url('nav_hd.png'); +--group-header-separator-color: #303030; +--group-header-color: #A0A0A0; +--inherit-header-color: #A0A0A0; + +--footer-foreground-color: #767676; +--footer-logo-width: 60px; +--citation-label-color: #A0A0A0; +--glow-color: cyan; + +--title-background-color: #080808; +--title-separator-color: #434343; +--directory-separator-color: #303030; +--separator-color: #303030; + +--blockquote-background-color: #101010; +--blockquote-border-color: #303030; + +--scrollbar-thumb-color: #303030; +--scrollbar-background-color: #060606; + +--icon-background-color: #404040; +--icon-foreground-color: #CCCCCC; +--icon-doc-image: url('docd.svg'); +--icon-folder-open-image: url('folderopend.svg'); +--icon-folder-closed-image: url('folderclosedd.svg'); + +/* brief member declaration list */ +--memdecl-background-color: #0A0A0A; +--memdecl-separator-color: #353535; +--memdecl-foreground-color: #BBB; +--memdecl-template-color: #909090; + +/* detailed member list */ +--memdef-border-color: #282828; +--memdef-title-background-color: #1E1E1E; +--memdef-title-gradient-image: url('nav_fd.png'); +--memdef-proto-background-color: #1B1B1B; +--memdef-proto-text-color: #ABABAB; +--memdef-proto-text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.9); +--memdef-doc-background-color: black; +--memdef-param-name-color: #D28757; +--memdef-template-color: #909090; + +/* tables */ +--table-cell-border-color: #303030; +--table-header-background-color: #303030; +--table-header-foreground-color: #CCCCCC; + +/* labels */ +--label-background-color: #444444; +--label-left-top-border-color: #606060; +--label-right-bottom-border-color: #303030; +--label-foreground-color: #CCCCCC; + +/** navigation bar/tree/menu */ +--nav-background-color: #101010; +--nav-foreground-color: #454545; +--nav-gradient-image: url('tab_bd.png'); +--nav-gradient-hover-image: url('tab_hd.png'); +--nav-gradient-active-image: url('tab_ad.png'); +--nav-gradient-active-image-parent: url("../tab_ad.png"); +--nav-separator-image: url('tab_sd.png'); +--nav-breadcrumb-image: url('bc_sd.png'); +--nav-breadcrumb-border-color: #333333; +--nav-splitbar-image: url('splitbard.png'); +--nav-font-size-level1: 13px; +--nav-font-size-level2: 10px; +--nav-font-size-level3: 9px; +--nav-text-normal-color: #C0C0C0; +--nav-text-hover-color: #E0E0E0; +--nav-text-active-color: #E0E0E0; +--nav-text-normal-shadow: 0px 1px 1px black; +--nav-text-hover-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); +--nav-text-active-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); +--nav-menu-button-color: #C0C0C0; +--nav-menu-background-color: #040404; +--nav-menu-foreground-color: #BBBBBB; +--nav-menu-toggle-color: rgba(255, 255, 255, 0.2); +--nav-arrow-color: #404040; +--nav-arrow-selected-color: #A0A0A0; + +/* table of contents */ +--toc-background-color: #151515; +--toc-border-color: #242424; +--toc-header-color: #B0B0B0; +--toc-down-arrow-image: url("data:image/svg+xml;utf8,&%238595;"); + +/** search field */ +--search-background-color: black; +--search-foreground-color: #C5C5C5; +--search-magnification-image: url('mag_d.svg'); +--search-magnification-select-image: url('mag_seld.svg'); +--search-active-color: #C5C5C5; +--search-filter-background-color: #101010; +--search-filter-foreground-color: #A0A0A0; +--search-filter-border-color: #909090; +--search-filter-highlight-text-color: #C5C5C5; +--search-filter-highlight-bg-color: #303030; +--search-results-background-color: #101010; +--search-results-foreground-color: #A0A0A0; +--search-results-border-color: #909090; +--search-box-shadow: inset 0.5px 0.5px 3px 0px #3A3A3A; + +/** code fragments */ +--code-keyword-color: #CC99CD; +--code-type-keyword-color: #AB99CD; +--code-flow-keyword-color: #E08000; +--code-comment-color: #717790; +--code-preprocessor-color: #65CABE; +--code-string-literal-color: #7EC699; +--code-char-literal-color: #00E0F0; +--code-xml-cdata-color: #C9D1D9; +--code-vhdl-digit-color: #FF00FF; +--code-vhdl-char-color: #C0C0C0; +--code-vhdl-keyword-color: #CF53C9; +--code-vhdl-logic-color: #FF0000; +--code-link-color: #79C0FF; +--code-external-link-color: #79C0FF; +--fragment-foreground-color: #C9D1D9; +--fragment-background-color: #080808; +--fragment-border-color: #30363D; +--fragment-lineno-border-color: #30363D; +--fragment-lineno-background-color: black; +--fragment-lineno-foreground-color: #6E7681; +--fragment-lineno-link-fg-color: #6E7681; +--fragment-lineno-link-bg-color: #303030; +--fragment-lineno-link-hover-fg-color: #8E96A1; +--fragment-lineno-link-hover-bg-color: #505050; +--fragment-copy-ok-color: #0EA80E; +--tooltip-foreground-color: #C9D1D9; +--tooltip-background-color: #202020; +--tooltip-border-color: #C9D1D9; +--tooltip-doc-color: #D9E1E9; +--tooltip-declaration-color: #20C348; +--tooltip-link-color: #79C0FF; +--tooltip-shadow: none; +--fold-line-color: #808080; +--fold-minus-image: url('minusd.svg'); +--fold-plus-image: url('plusd.svg'); +--fold-minus-image-relpath: url('../../minusd.svg'); +--fold-plus-image-relpath: url('../../plusd.svg'); + +/** font-family */ +--font-family-normal: Roboto,sans-serif; +--font-family-monospace: 'JetBrains Mono',Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace,fixed; +--font-family-nav: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; +--font-family-title: Tahoma,Arial,sans-serif; +--font-family-toc: Verdana,'DejaVu Sans',Geneva,sans-serif; +--font-family-search: Arial,Verdana,sans-serif; +--font-family-icon: Arial,Helvetica; +--font-family-tooltip: Roboto,sans-serif; + +/** special sections */ +--warning-color-bg: #2e1917; +--warning-color-hl: #ad2617; +--warning-color-text: #f5b1aa; +--note-color-bg: #3b2e04; +--note-color-hl: #f1b602; +--note-color-text: #ceb670; +--todo-color-bg: #163750; +--todo-color-hl: #1982D2; +--todo-color-text: #dcf0fa; +--test-color-bg: #121258; +--test-color-hl: #4242cf; +--test-color-text: #c0c0da; +--deprecated-color-bg: #2e323b; +--deprecated-color-hl: #738396; +--deprecated-color-text: #abb0bd; +--bug-color-bg: #2a2536; +--bug-color-hl: #7661b3; +--bug-color-text: #ae9ed6; +--invariant-color-bg: #303a35; +--invariant-color-hl: #76ce96; +--invariant-color-text: #cceed5; +} + +body { + background-color: var(--page-background-color); + color: var(--page-foreground-color); +} + +body, table, div, p, dl { + font-weight: 400; + font-size: 14px; + font-family: var(--font-family-normal); + line-height: 22px; +} + +/* @group Heading Levels */ + +.title { + font-family: var(--font-family-normal); + line-height: 28px; + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h1.groupheader { + font-size: 150%; +} + +h2.groupheader { + border-bottom: 1px solid var(--group-header-separator-color); + color: var(--group-header-color); + font-size: 150%; + font-weight: normal; + margin-top: 1.75em; + padding-top: 8px; + padding-bottom: 4px; + width: 100%; +} + +h3.groupheader { + font-size: 100%; +} + +h1, h2, h3, h4, h5, h6 { + -webkit-transition: text-shadow 0.5s linear; + -moz-transition: text-shadow 0.5s linear; + -ms-transition: text-shadow 0.5s linear; + -o-transition: text-shadow 0.5s linear; + transition: text-shadow 0.5s linear; + margin-right: 15px; +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px var(--glow-color); +} + +dt { + font-weight: bold; +} + +p.startli, p.startdd { + margin-top: 2px; +} + +th p.starttd, th p.intertd, th p.endtd { + font-size: 100%; + font-weight: 700; +} + +p.starttd { + margin-top: 0px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +p.interli { +} + +p.interdd { +} + +p.intertd { +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.navtab { + padding-right: 15px; + text-align: right; + line-height: 110%; +} + +div.navtab table { + border-spacing: 0; +} + +td.navtab { + padding-right: 6px; + padding-left: 6px; +} + +td.navtabHL { + background-image: var(--nav-gradient-active-image); + background-repeat:repeat-x; + padding-right: 6px; + padding-left: 6px; +} + +td.navtabHL a, td.navtabHL a:visited { + color: var(--nav-text-hover-color); + text-shadow: var(--nav-text-hover-shadow); +} + +a.navtab { + font-weight: bold; +} + +div.qindex{ + text-align: center; + width: 100%; + line-height: 140%; + font-size: 130%; + color: var(--index-separator-color); +} + +#main-menu a:focus { + outline: auto; + z-index: 10; + position: relative; +} + +dt.alphachar{ + font-size: 180%; + font-weight: bold; +} + +.alphachar a{ + color: var(--index-header-color); +} + +.alphachar a:hover, .alphachar a:visited{ + text-decoration: none; +} + +.classindex dl { + padding: 25px; + column-count:1 +} + +.classindex dd { + display:inline-block; + margin-left: 50px; + width: 90%; + line-height: 1.15em; +} + +.classindex dl.even { + background-color: var(--index-even-item-bg-color); +} + +.classindex dl.odd { + background-color: var(--index-odd-item-bg-color); +} + +@media(min-width: 1120px) { + .classindex dl { + column-count:2 + } +} + +@media(min-width: 1320px) { + .classindex dl { + column-count:3 + } +} + + +/* @group Link Styling */ + +a { + color: var(--page-link-color); + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: var(--page-visited-link-color); +} + +a:hover { + text-decoration: none; + background: linear-gradient(to bottom, transparent 0,transparent calc(100% - 1px), currentColor 100%); +} + +a:hover > span.arrow { + text-decoration: none; + background : var(--nav-background-color); +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited, a.line, a.line:visited { + color: var(--code-link-color); +} + +a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited { + color: var(--code-external-link-color); +} + +a.code.hl_class { /* style for links to class names in code snippets */ } +a.code.hl_struct { /* style for links to struct names in code snippets */ } +a.code.hl_union { /* style for links to union names in code snippets */ } +a.code.hl_interface { /* style for links to interface names in code snippets */ } +a.code.hl_protocol { /* style for links to protocol names in code snippets */ } +a.code.hl_category { /* style for links to category names in code snippets */ } +a.code.hl_exception { /* style for links to exception names in code snippets */ } +a.code.hl_service { /* style for links to service names in code snippets */ } +a.code.hl_singleton { /* style for links to singleton names in code snippets */ } +a.code.hl_concept { /* style for links to concept names in code snippets */ } +a.code.hl_namespace { /* style for links to namespace names in code snippets */ } +a.code.hl_package { /* style for links to package names in code snippets */ } +a.code.hl_define { /* style for links to macro names in code snippets */ } +a.code.hl_function { /* style for links to function names in code snippets */ } +a.code.hl_variable { /* style for links to variable names in code snippets */ } +a.code.hl_typedef { /* style for links to typedef names in code snippets */ } +a.code.hl_enumvalue { /* style for links to enum value names in code snippets */ } +a.code.hl_enumeration { /* style for links to enumeration names in code snippets */ } +a.code.hl_signal { /* style for links to Qt signal names in code snippets */ } +a.code.hl_slot { /* style for links to Qt slot names in code snippets */ } +a.code.hl_friend { /* style for links to friend names in code snippets */ } +a.code.hl_dcop { /* style for links to KDE3 DCOP names in code snippets */ } +a.code.hl_property { /* style for links to property names in code snippets */ } +a.code.hl_event { /* style for links to event names in code snippets */ } +a.code.hl_sequence { /* style for links to sequence names in code snippets */ } +a.code.hl_dictionary { /* style for links to dictionary names in code snippets */ } + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +ul { + overflow: visible; +} + +ul.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; + column-count: 3; + list-style-type: none; +} + +#side-nav ul { + overflow: visible; /* reset ul rule for scroll bar in GENERATE_TREEVIEW window */ +} + +#main-nav ul { + overflow: visible; /* reset ul rule for the navigation bar drop down lists */ +} + +.fragment { + text-align: left; + direction: ltr; + overflow-x: auto; + overflow-y: hidden; + position: relative; + min-height: 12px; + margin: 10px 0px; + padding: 10px 10px; + border: 1px solid var(--fragment-border-color); + border-radius: 4px; + background-color: var(--fragment-background-color); + color: var(--fragment-foreground-color); +} + +pre.fragment { + word-wrap: break-word; + font-size: 10pt; + line-height: 125%; + font-family: var(--font-family-monospace); +} + +.clipboard { + width: 24px; + height: 24px; + right: 5px; + top: 5px; + opacity: 0; + position: absolute; + display: inline; + overflow: auto; + fill: var(--fragment-foreground-color); + justify-content: center; + align-items: center; + cursor: pointer; +} + +.clipboard.success { + border: 1px solid var(--fragment-foreground-color); + border-radius: 4px; +} + +.fragment:hover .clipboard, .clipboard.success { + opacity: .28; +} + +.clipboard:hover, .clipboard.success { + opacity: 1 !important; +} + +.clipboard:active:not([class~=success]) svg { + transform: scale(.91); +} + +.clipboard.success svg { + fill: var(--fragment-copy-ok-color); +} + +.clipboard.success { + border-color: var(--fragment-copy-ok-color); +} + +div.line { + font-family: var(--font-family-monospace); + font-size: 13px; + min-height: 13px; + line-height: 1.2; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + text-indent: -53px; + padding-left: 53px; + padding-bottom: 0px; + margin: 0px; + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +div.line:after { + content:"\000A"; + white-space: pre; +} + +div.line.glow { + background-color: var(--glow-color); + box-shadow: 0 0 10px var(--glow-color); +} + +span.fold { + margin-left: 5px; + margin-right: 1px; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; + display: inline-block; + width: 12px; + height: 12px; + background-repeat:no-repeat; + background-position:center; +} + +span.lineno { + padding-right: 4px; + margin-right: 9px; + text-align: right; + border-right: 2px solid var(--fragment-lineno-border-color); + color: var(--fragment-lineno-foreground-color); + background-color: var(--fragment-lineno-background-color); + white-space: pre; +} +span.lineno a, span.lineno a:visited { + color: var(--fragment-lineno-link-fg-color); + background-color: var(--fragment-lineno-link-bg-color); +} + +span.lineno a:hover { + color: var(--fragment-lineno-link-hover-fg-color); + background-color: var(--fragment-lineno-link-hover-bg-color); +} + +.lineno { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +div.classindex ul { + list-style: none; + padding-left: 0; +} + +div.classindex span.ai { + display: inline-block; +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + color: var(--page-foreground-color); + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 12px; + margin-right: 8px; +} + +p.formulaDsp { + text-align: center; +} + +img.dark-mode-visible { + display: none; +} +img.light-mode-visible { + display: none; +} + +img.formulaInl, img.inline { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; + width: var(--footer-logo-width); +} + +.compoundTemplParams { + color: var(--memdecl-template-color); + font-size: 80%; + line-height: 120%; +} + +/* @group Code Colorization */ + +span.keyword { + color: var(--code-keyword-color); +} + +span.keywordtype { + color: var(--code-type-keyword-color); +} + +span.keywordflow { + color: var(--code-flow-keyword-color); +} + +span.comment { + color: var(--code-comment-color); +} + +span.preprocessor { + color: var(--code-preprocessor-color); +} + +span.stringliteral { + color: var(--code-string-literal-color); +} + +span.charliteral { + color: var(--code-char-literal-color); +} + +span.xmlcdata { + color: var(--code-xml-cdata-color); +} + +span.vhdldigit { + color: var(--code-vhdl-digit-color); +} + +span.vhdlchar { + color: var(--code-vhdl-char-color); +} + +span.vhdlkeyword { + color: var(--code-vhdl-keyword-color); +} + +span.vhdllogic { + color: var(--code-vhdl-logic-color); +} + +blockquote { + background-color: var(--blockquote-background-color); + border-left: 2px solid var(--blockquote-border-color); + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + +/* @end */ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid var(--table-cell-border-color); +} + +th.dirtab { + background-color: var(--table-header-background-color); + color: var(--table-header-foreground-color); + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid var(--separator-color); +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.memberdecls td, .fieldtable tr { + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: var(--glow-color); + box-shadow: 0 0 15px var(--glow-color); +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: var(--memdecl-background-color); + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: var(--memdecl-foreground-color); +} + +.memSeparator { + border-bottom: 1px solid var(--memdecl-separator-color); + line-height: 1px; + margin: 0px; + padding: 0px; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight, .memTemplItemRight { + width: 100%; +} + +.memTemplParams { + color: var(--memdecl-template-color); + white-space: nowrap; + font-size: 80%; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtitle { + padding: 8px; + border-top: 1px solid var(--memdef-border-color); + border-left: 1px solid var(--memdef-border-color); + border-right: 1px solid var(--memdef-border-color); + border-top-right-radius: 4px; + border-top-left-radius: 4px; + margin-bottom: -1px; + background-image: var(--memdef-title-gradient-image); + background-repeat: repeat-x; + background-color: var(--memdef-title-background-color); + line-height: 1.25; + font-weight: 300; + float:left; +} + +.permalink +{ + font-size: 65%; + display: inline-block; + vertical-align: middle; +} + +.memtemplate { + font-size: 80%; + color: var(--memdef-template-color); + font-weight: normal; + margin-left: 9px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; + -webkit-transition: box-shadow 0.5s linear; + -moz-transition: box-shadow 0.5s linear; + -ms-transition: box-shadow 0.5s linear; + -o-transition: box-shadow 0.5s linear; + transition: box-shadow 0.5s linear; + display: table !important; + width: 100%; +} + +.memitem.glow { + box-shadow: 0 0 15px var(--glow-color); +} + +.memname { + font-weight: 400; + margin-left: 6px; +} + +.memname td { + vertical-align: bottom; +} + +.memproto, dl.reflist dt { + border-top: 1px solid var(--memdef-border-color); + border-left: 1px solid var(--memdef-border-color); + border-right: 1px solid var(--memdef-border-color); + padding: 6px 0px 6px 0px; + color: var(--memdef-proto-text-color); + font-weight: bold; + text-shadow: var(--memdef-proto-text-shadow); + background-color: var(--memdef-proto-background-color); + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 4px; +} + +.overload { + font-family: var(--font-family-monospace); + font-size: 65%; +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid var(--memdef-border-color); + border-left: 1px solid var(--memdef-border-color); + border-right: 1px solid var(--memdef-border-color); + padding: 6px 10px 2px 10px; + border-top-width: 0; + background-image:url('nav_g.png'); + background-repeat:repeat-x; + background-color: var(--memdef-doc-background-color); + /* opera specific markup */ + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-bottomright: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; + padding: 0px; + padding-bottom: 1px; +} + +.paramname { + white-space: nowrap; + padding: 0px; + padding-bottom: 1px; + margin-left: 2px; +} + +.paramname em { + color: var(--memdef-param-name-color); + font-style: normal; + margin-right: 1px; +} + +.paramname .paramdefval { + font-family: var(--font-family-monospace); +} + +.params, .retval, .exception, .tparams { + margin-left: 0px; + padding-left: 0px; +} + +.params .paramname, .retval .paramname, .tparams .paramname, .exception .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype, .tparams .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir, .tparams .paramdir { + font-family: var(--font-family-monospace); + vertical-align: top; +} + +table.mlabels { + border-spacing: 0px; +} + +td.mlabels-left { + width: 100%; + padding: 0px; +} + +td.mlabels-right { + vertical-align: bottom; + padding: 0px; + white-space: nowrap; +} + +span.mlabels { + margin-left: 8px; +} + +span.mlabel { + background-color: var(--label-background-color); + border-top:1px solid var(--label-left-top-border-color); + border-left:1px solid var(--label-left-top-border-color); + border-right:1px solid var(--label-right-bottom-border-color); + border-bottom:1px solid var(--label-right-bottom-border-color); + text-shadow: none; + color: var(--label-foreground-color); + margin-right: 4px; + padding: 2px 3px; + border-radius: 3px; + font-size: 7pt; + white-space: nowrap; + vertical-align: middle; +} + + + +/* @end */ + +/* these are for tree view inside a (index) page */ + +div.directory { + margin: 10px 0px; + border-top: 1px solid var(--directory-separator-color); + border-bottom: 1px solid var(--directory-separator-color); + width: 100%; +} + +.directory table { + border-collapse:collapse; +} + +.directory td { + margin: 0px; + padding: 0px; + vertical-align: top; +} + +.directory td.entry { + white-space: nowrap; + padding-right: 6px; + padding-top: 3px; +} + +.directory td.entry a { + outline:none; +} + +.directory td.entry a img { + border: none; +} + +.directory td.desc { + width: 100%; + padding-left: 6px; + padding-right: 6px; + padding-top: 3px; + border-left: 1px solid rgba(0,0,0,0.05); +} + +.directory tr.odd { + padding-left: 6px; + background-color: var(--index-odd-item-bg-color); +} + +.directory tr.even { + padding-left: 6px; + background-color: var(--index-even-item-bg-color); +} + +.directory img { + vertical-align: -30%; +} + +.directory .levels { + white-space: nowrap; + width: 100%; + text-align: right; + font-size: 9pt; +} + +.directory .levels span { + cursor: pointer; + padding-left: 2px; + padding-right: 2px; + color: var(--page-link-color); +} + +.arrow { + color: var(--nav-arrow-color); + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: pointer; + font-size: 80%; + display: inline-block; + width: 16px; + height: 22px; +} + +.icon { + font-family: var(--font-family-icon); + line-height: normal; + font-weight: bold; + font-size: 12px; + height: 14px; + width: 16px; + display: inline-block; + background-color: var(--icon-background-color); + color: var(--icon-foreground-color); + text-align: center; + border-radius: 4px; + margin-left: 2px; + margin-right: 2px; +} + +.icona { + width: 24px; + height: 22px; + display: inline-block; +} + +.iconfopen { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:var(--icon-folder-open-image); + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.iconfclosed { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:var(--icon-folder-closed-image); + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.icondoc { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:var(--icon-doc-image); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +address { + font-style: normal; + color: var(--footer-foreground-color); +} + +table.doxtable caption { + caption-side: top; +} + +table.doxtable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.doxtable td, table.doxtable th { + border: 1px solid var(--table-cell-border-color); + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: var(--table-header-background-color); + color: var(--table-header-foreground-color); + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +table.fieldtable { + margin-bottom: 10px; + border: 1px solid var(--memdef-border-color); + border-spacing: 0px; + border-radius: 4px; + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid var(--memdef-border-color); + border-bottom: 1px solid var(--memdef-border-color); + vertical-align: top; +} + +.fieldtable td.fieldname { + padding-top: 3px; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid var(--memdef-border-color); +} + +.fieldtable td.fielddoc p:first-child { + margin-top: 0px; +} + +.fieldtable td.fielddoc p:last-child { + margin-bottom: 2px; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image: var(--memdef-title-gradient-image); + background-repeat:repeat-x; + background-color: var(--memdef-title-background-color); + font-size: 90%; + color: var(--memdef-proto-text-color); + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + font-weight: 400; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid var(--memdef-border-color); +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: var(--nav-gradient-image); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image: var(--nav-gradient-image); + background-repeat:repeat-x; + background-position: 0 -5px; + height:30px; + line-height:30px; + color:var(--nav-text-normal-color); + border:solid 1px var(--nav-breadcrumb-border-color); + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:var(--nav-breadcrumb-image); + background-repeat:no-repeat; + background-position:right; + color: var(--nav-foreground-color); +} + +.navpath li.navelem a +{ + height:32px; + display:block; + outline: none; + color: var(--nav-text-normal-color); + font-family: var(--font-family-nav); + text-shadow: var(--nav-text-normal-shadow); + text-decoration: none; +} + +.navpath li.navelem a:hover +{ + color: var(--nav-text-hover-color); + text-shadow: var(--nav-text-hover-shadow); +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color: var(--footer-foreground-color); + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +table.classindex +{ + margin: 10px; + white-space: nowrap; + margin-left: 3%; + margin-right: 3%; + width: 94%; + border: 0; + border-spacing: 0; + padding: 0; +} + +div.ingroups +{ + font-size: 8pt; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image: var(--header-gradient-image); + background-repeat:repeat-x; + background-color: var(--header-background-color); + margin: 0px; + border-bottom: 1px solid var(--header-separator-color); +} + +div.headertitle +{ + padding: 5px 5px 5px 10px; +} + +.PageDocRTL-title div.headertitle { + text-align: right; + direction: rtl; +} + +dl { + padding: 0 0 0 0; +} + +/* + +dl.section { + margin-left: 0px; + padding-left: 0px; +} + +dl.note { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #D0C000; +} + +dl.warning, dl.attention { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #00D000; +} + +dl.deprecated { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #505050; +} + +dl.todo { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #00C0E0; +} + +dl.test { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #3030E0; +} + +dl.bug { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #C08050; +} + +*/ + +dl.bug dt a, dl.deprecated dt a, dl.todo dt a, dl.test a { + font-weight: bold !important; +} + +dl.warning, dl.attention, dl.note, dl.deprecated, dl.bug, +dl.invariant, dl.pre, dl.post, dl.todo, dl.test, dl.remark { + padding: 10px; + margin: 10px 0px; + overflow: hidden; + margin-left: 0; + border-radius: 4px; +} + +dl.section dd { + margin-bottom: 2px; +} + +dl.warning, dl.attention { + background: var(--warning-color-bg); + border-left: 8px solid var(--warning-color-hl); + color: var(--warning-color-text); +} + +dl.warning dt, dl.attention dt { + color: var(--warning-color-hl); +} + +dl.note, dl.remark { + background: var(--note-color-bg); + border-left: 8px solid var(--note-color-hl); + color: var(--note-color-text); +} + +dl.note dt, dl.remark dt { + color: var(--note-color-hl); +} + +dl.todo { + background: var(--todo-color-bg); + border-left: 8px solid var(--todo-color-hl); + color: var(--todo-color-text); +} + +dl.todo dt { + color: var(--todo-color-hl); +} + +dl.test { + background: var(--test-color-bg); + border-left: 8px solid var(--test-color-hl); + color: var(--test-color-text); +} + +dl.test dt { + color: var(--test-color-hl); +} + +dl.bug dt a { + color: var(--bug-color-hl) !important; +} + +dl.bug { + background: var(--bug-color-bg); + border-left: 8px solid var(--bug-color-hl); + color: var(--bug-color-text); +} + +dl.bug dt a { + color: var(--bug-color-hl) !important; +} + +dl.deprecated { + background: var(--deprecated-color-bg); + border-left: 8px solid var(--deprecated-color-hl); + color: var(--deprecated-color-text); +} + +dl.deprecated dt a { + color: var(--deprecated-color-hl) !important; +} + +dl.section dd, dl.bug dd, dl.deprecated dd, dl.todo dd, dl.test dd { + margin-inline-start: 0px; +} + +dl.invariant, dl.pre, dl.post { + background: var(--invariant-color-bg); + border-left: 8px solid var(--invariant-color-hl); + color: var(--invariant-color-text); +} + +dl.invariant dt, dl.pre dt, dl.post dt { + color: var(--invariant-color-hl); +} + + +#projectrow +{ + height: 56px; +} + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectalign +{ + vertical-align: middle; + padding-left: 0.5em; +} + +#projectname +{ + font-size: 200%; + font-family: var(--font-family-title); + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font-size: 90%; + font-family: var(--font-family-title); + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font-size: 50%; + font-family: 50% var(--font-family-title); + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid var(--title-separator-color); + background-color: var(--title-background-color); +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.plantumlgraph +{ + text-align: center; +} + +.diagraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:var(--citation-label-color); + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; + text-align:right; + width:52px; +} + +dl.citelist dd { + margin:2px 0 2px 72px; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: var(--toc-background-color); + border: 1px solid var(--toc-border-color); + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 8px 10px 10px; + width: 200px; +} + +div.toc li { + background: var(--toc-down-arrow-image) no-repeat scroll 0 5px transparent; + font: 10px/1.2 var(--font-family-toc); + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +div.toc h3 { + font: bold 12px/1.2 var(--font-family-toc); + color: var(--toc-header-color); + border-bottom: 0 none; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 15px; +} + +div.toc li.level4 { + margin-left: 15px; +} + +span.emoji { + /* font family used at the site: https://unicode.org/emoji/charts/full-emoji-list.html + * font-family: "Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", Times, Symbola, Aegyptus, Code2000, Code2001, Code2002, Musica, serif, LastResort; + */ +} + +span.obfuscator { + display: none; +} + +.inherit_header { + font-weight: bold; + color: var(--inherit-header-color); + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.inherit_header td { + padding: 6px 0px 2px 5px; +} + +.inherit { + display: none; +} + +tr.heading h2 { + margin-top: 12px; + margin-bottom: 4px; +} + +/* tooltip related style info */ + +.ttc { + position: absolute; + display: none; +} + +#powerTip { + cursor: default; + /*white-space: nowrap;*/ + color: var(--tooltip-foreground-color); + background-color: var(--tooltip-background-color); + border: 1px solid var(--tooltip-border-color); + border-radius: 4px 4px 4px 4px; + box-shadow: var(--tooltip-shadow); + display: none; + font-size: smaller; + max-width: 80%; + opacity: 0.9; + padding: 1ex 1em 1em; + position: absolute; + z-index: 2147483647; +} + +#powerTip div.ttdoc { + color: var(--tooltip-doc-color); + font-style: italic; +} + +#powerTip div.ttname a { + font-weight: bold; +} + +#powerTip a { + color: var(--tooltip-link-color); +} + +#powerTip div.ttname { + font-weight: bold; +} + +#powerTip div.ttdeci { + color: var(--tooltip-declaration-color); +} + +#powerTip div { + margin: 0px; + padding: 0px; + font-size: 12px; + font-family: var(--font-family-tooltip); + line-height: 16px; +} + +#powerTip:before, #powerTip:after { + content: ""; + position: absolute; + margin: 0px; +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.s:after, #powerTip.s:before, +#powerTip.w:after, #powerTip.w:before, +#powerTip.e:after, #powerTip.e:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.nw:after, #powerTip.nw:before, +#powerTip.sw:after, #powerTip.sw:before { + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; +} + +#powerTip.n:after, #powerTip.s:after, +#powerTip.w:after, #powerTip.e:after, +#powerTip.nw:after, #powerTip.ne:after, +#powerTip.sw:after, #powerTip.se:after { + border-color: rgba(255, 255, 255, 0); +} + +#powerTip.n:before, #powerTip.s:before, +#powerTip.w:before, #powerTip.e:before, +#powerTip.nw:before, #powerTip.ne:before, +#powerTip.sw:before, #powerTip.se:before { + border-color: rgba(128, 128, 128, 0); +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.nw:after, #powerTip.nw:before { + top: 100%; +} + +#powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after { + border-top-color: var(--tooltip-background-color); + border-width: 10px; + margin: 0px -10px; +} +#powerTip.n:before, #powerTip.ne:before, #powerTip.nw:before { + border-top-color: var(--tooltip-border-color); + border-width: 11px; + margin: 0px -11px; +} +#powerTip.n:after, #powerTip.n:before { + left: 50%; +} + +#powerTip.nw:after, #powerTip.nw:before { + right: 14px; +} + +#powerTip.ne:after, #powerTip.ne:before { + left: 14px; +} + +#powerTip.s:after, #powerTip.s:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.sw:after, #powerTip.sw:before { + bottom: 100%; +} + +#powerTip.s:after, #powerTip.se:after, #powerTip.sw:after { + border-bottom-color: var(--tooltip-background-color); + border-width: 10px; + margin: 0px -10px; +} + +#powerTip.s:before, #powerTip.se:before, #powerTip.sw:before { + border-bottom-color: var(--tooltip-border-color); + border-width: 11px; + margin: 0px -11px; +} + +#powerTip.s:after, #powerTip.s:before { + left: 50%; +} + +#powerTip.sw:after, #powerTip.sw:before { + right: 14px; +} + +#powerTip.se:after, #powerTip.se:before { + left: 14px; +} + +#powerTip.e:after, #powerTip.e:before { + left: 100%; +} +#powerTip.e:after { + border-left-color: var(--tooltip-border-color); + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.e:before { + border-left-color: var(--tooltip-border-color); + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +#powerTip.w:after, #powerTip.w:before { + right: 100%; +} +#powerTip.w:after { + border-right-color: var(--tooltip-border-color); + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.w:before { + border-right-color: var(--tooltip-border-color); + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } +} + +/* @group Markdown */ + +table.markdownTable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.markdownTable td, table.markdownTable th { + border: 1px solid var(--table-cell-border-color); + padding: 3px 7px 2px; +} + +table.markdownTable tr { +} + +th.markdownTableHeadLeft, th.markdownTableHeadRight, th.markdownTableHeadCenter, th.markdownTableHeadNone { + background-color: var(--table-header-background-color); + color: var(--table-header-foreground-color); + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +th.markdownTableHeadLeft, td.markdownTableBodyLeft { + text-align: left +} + +th.markdownTableHeadRight, td.markdownTableBodyRight { + text-align: right +} + +th.markdownTableHeadCenter, td.markdownTableBodyCenter { + text-align: center +} + +tt, code, kbd, samp +{ + display: inline-block; +} +/* @end */ + +u { + text-decoration: underline; +} + +details>summary { + list-style-type: none; +} + +details > summary::-webkit-details-marker { + display: none; +} + +details>summary::before { + content: "\25ba"; + padding-right:4px; + font-size: 80%; +} + +details[open]>summary::before { + content: "\25bc"; + padding-right:4px; + font-size: 80%; +} + diff --git a/apidoc/html/doxygen.svg b/apidoc/html/doxygen.svg new file mode 100644 index 0000000..4c6ad67 --- /dev/null +++ b/apidoc/html/doxygen.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apidoc/html/doxygen_crawl.html b/apidoc/html/doxygen_crawl.html new file mode 100644 index 0000000..92e8b02 --- /dev/null +++ b/apidoc/html/doxygen_crawl.html @@ -0,0 +1,75 @@ + + + +Validator / crawler helper + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apidoc/html/doxygen_extra.css b/apidoc/html/doxygen_extra.css new file mode 100644 index 0000000..953f03b --- /dev/null +++ b/apidoc/html/doxygen_extra.css @@ -0,0 +1,181 @@ +* { + font-family: "Roboto", "Calibri", "Arial", sans-serif; +} + +.headertitle { + font-size: 125%; +} + +#nav-tree .label { + font-size: 110%; +} + +p, li { + font-size: 110%; +} + +h1, h2, h3, h4, h5, h6 { + margin-top: 24px; + margin-bottom: 16px; + font-weight: 600; + line-height: 1.25; + color: #8d0034; +} + +h1 { + font-size: 200%; + padding-top: 1em; + padding-bottom: 0.3em; + border-bottom: 2px solid; +} + +h2 { + font-size: 170%; + padding-top: 0.3em; + padding-bottom: 0.2em; + border-bottom: 1px solid; +} + +h3 { + font-size: 150%; +} + +h4 { + font-size: 125%; +} + +h5 { + font-size: 110%; +} + +h6 { + font-size: 87.5%; + color: #283266; +} + +div.fragment { + padding: 4px 16px 4px 16px; + border: 0px solid; +} + +.line, .keywordflow { + font-family: "Roboto Mono", "Calibri Mono", "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; + line-height: 1.8; +} + +span.comment { + color: #555D68; +} + + +div.line.glow { + background-color: auto; + box-shadow: none; + font-weight: bold; +} + +hr { + display: none; +} + +code { + font-family: "Roboto Mono", "Calibri Mono", "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0px 2px 0px 2px; + font-size: 87.5%; + font-weight: bold; +} + +a.hl_function, a.hl_struct, span.keywordtype, span.keywordflow { + font-weight: bold; +} + +span.keywordflow { + color: #C6809A; +} + +a { + color: var(--page-link-color); +} + +a:visited, a.dark-mode { + color: #894270; +} + +#main-nav a { + color: var(--menu-link-color); +} + +#main-menu a { + color: var(--menu-link-color); +} + +#nav-tree-contents a { + color: var(--menu-link-color); +} + +/* tint 15/85 80%: 894270 */ +/* tint 30/70 482562 -> 80%: 6D5182 */ +/* tint 50/50 5C1B55 */ +/* tint 70/30 701048 */ +/* 80% red A4335D */ +/* 100% blue 283266 */ +/* 80% blue 555DA3 */ +/* 70% blue 6B719E */ +/* 60% blue 8086AC */ +/* 50% blue 959ABA */ +/* 40% blue AAAEC8 */ +html { + --title-background-color: #D8D8D8; + --nav-background-color: #F0F0F0; + --memdef-title-background-color: #D8D8D8; + --memdef-proto-background-color: #D8D8D8; + --memdef-doc-background-color: #F0F0F0; + --fragment-foreground-color: #283266; + --menu-link-color: #303030; + --page-link-color: #8d0034; + --code-link-color: #8d0034; + --page-visited-link-color: #701048; + --code-type-keyword-color: #5C1B55; + --memdef-proto-text-color: #283266; +} + +html.dark-mode { + --title-background-color: #181818; + --page-background-color: black; + --nav-background-color: black; + --memdef-title-background-color: #181818; + --memdef-proto-background-color: #181818; + --memdef-doc-background-color: #303030; + --fragment-foreground-color: #959ABA; + --menu-link-color: #D0D0D0; + --page-link-color: #A4335D; + --code-link-color: #A4335D; + --page-visited-link-color: #894270; + --code-type-keyword-color: #6D5182; + --memdef-proto-text-color: #555DA3; +} + +.paramtype { + color: var(--code-type-keyword-color); +} + +.paramname { + color: #BB0085; +} + +.memtitle { + font-weight: bold; +} + +.memname { + font-weight: bold; + color: var(--fragment-foreground-color); +} + + +blockquote { + border-left: 2px solid #606060; + margin: 0 24px 0 4px; + padding: 0px 12px 0px 16px; +} + diff --git a/apidoc/html/dynsections.js b/apidoc/html/dynsections.js new file mode 100644 index 0000000..8f49326 --- /dev/null +++ b/apidoc/html/dynsections.js @@ -0,0 +1,194 @@ +/* + @licstart The following is the entire license notice for the JavaScript code in this file. + + The MIT License (MIT) + + Copyright (C) 1997-2020 by Dimitri van Heesch + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software + and associated documentation files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, publish, distribute, + sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + @licend The above is the entire license notice for the JavaScript code in this file + */ + +let dynsection = { + + // helper function + updateStripes : function() { + $('table.directory tr'). + removeClass('even').filter(':visible:even').addClass('even'); + $('table.directory tr'). + removeClass('odd').filter(':visible:odd').addClass('odd'); + }, + + toggleVisibility : function(linkObj) { + const base = $(linkObj).attr('id'); + const summary = $('#'+base+'-summary'); + const content = $('#'+base+'-content'); + const trigger = $('#'+base+'-trigger'); + const src=$(trigger).attr('src'); + if (content.is(':visible')===true) { + content.hide(); + summary.show(); + $(linkObj).addClass('closed').removeClass('opened'); + $(trigger).attr('src',src.substring(0,src.length-8)+'closed.png'); + } else { + content.show(); + summary.hide(); + $(linkObj).removeClass('closed').addClass('opened'); + $(trigger).attr('src',src.substring(0,src.length-10)+'open.png'); + } + return false; + }, + + toggleLevel : function(level) { + $('table.directory tr').each(function() { + const l = this.id.split('_').length-1; + const i = $('#img'+this.id.substring(3)); + const a = $('#arr'+this.id.substring(3)); + if (l'); + // add vertical lines to other rows + $('span[class=lineno]').not(':eq(0)').append(''); + // add toggle controls to lines with fold divs + $('div[class=foldopen]').each(function() { + // extract specific id to use + const id = $(this).attr('id').replace('foldopen',''); + // extract start and end foldable fragment attributes + const start = $(this).attr('data-start'); + const end = $(this).attr('data-end'); + // replace normal fold span with controls for the first line of a foldable fragment + $(this).find('span[class=fold]:first').replaceWith(''); + // append div for folded (closed) representation + $(this).after(''); + // extract the first line from the "open" section to represent closed content + const line = $(this).children().first().clone(); + // remove any glow that might still be active on the original line + $(line).removeClass('glow'); + if (start) { + // if line already ends with a start marker (e.g. trailing {), remove it + $(line).html($(line).html().replace(new RegExp('\\s*'+start+'\\s*$','g'),'')); + } + // replace minus with plus symbol + $(line).find('span[class=fold]').css('background-image',codefold.plusImg[relPath]); + // append ellipsis + $(line).append(' '+start+''+end); + // insert constructed line into closed div + $('#foldclosed'+id).html(line); + }); + }, +}; +/* @license-end */ diff --git a/apidoc/html/files.html b/apidoc/html/files.html new file mode 100644 index 0000000..63c8e13 --- /dev/null +++ b/apidoc/html/files.html @@ -0,0 +1,126 @@ + + + + + + + +smax-clib: File List + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
File List
+
+
+
Here is a list of all documented files with brief descriptions:
+
[detail level 12]
+ + + + + + + + + + + + +
  include
 smax-private.hA set of private SMA-X routines used by the API library but should not be exposed outside
 smax.h
  src
 smax-easy.cA set of functions for simplified access to SMA-X for specific variable types
 smax-lazy.cA set of functions to support the efficient retrieval of lazy variables, that is variables that change infrequently, from the SMA-X database. Rather than querying the database on every call, the first lazy pull of a variable initiates monitoring for updates. The pull requests will return the current state of the variable at all times, but it generates minimal network traffic only when the underlying value in the database is changed
 smax-messages.cSimple API for sending and receiving program broadcast messages through SMA-X
 smax-meta.cA set of utility functions for manipulating optional static metadata
 smax-queue.cFunctions to support pipelined pull requests from SMA-X. Because they don't requite a sequence of round-trips, pipelined pulls can be orders of magnitude faster than staggered regular pull requests
 smax-resilient.cThis module adds trusty push delivery to SMA-X. If the server cannot be reached, push requests are stored and updated locally until the server connection is restored, at which point they are delivered
 smax-util.cA collection of commonly used functions for the SMA-X library
 smax.cSMA-X is a software implementation for SMA shared data, and is the base layer for the software reflective memory (RM) emulation, and DSM replacement. It works by communicating TCP/IP messages to a central Redis server
+
+
+
+ + + + diff --git a/apidoc/html/files_dup.js b/apidoc/html/files_dup.js new file mode 100644 index 0000000..89e9042 --- /dev/null +++ b/apidoc/html/files_dup.js @@ -0,0 +1,5 @@ +var files_dup = +[ + [ "include", "dir_d44c64559bbebec7f509842c48db8b23.html", "dir_d44c64559bbebec7f509842c48db8b23" ], + [ "src", "dir_68267d1309a1af8e8297ef4c3efbcdba.html", "dir_68267d1309a1af8e8297ef4c3efbcdba" ] +]; \ No newline at end of file diff --git a/apidoc/html/folderclosed.svg b/apidoc/html/folderclosed.svg new file mode 100644 index 0000000..0e1f755 --- /dev/null +++ b/apidoc/html/folderclosed.svg @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/apidoc/html/folderclosedd.svg b/apidoc/html/folderclosedd.svg new file mode 100644 index 0000000..53f219f --- /dev/null +++ b/apidoc/html/folderclosedd.svg @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/apidoc/html/folderopen.svg b/apidoc/html/folderopen.svg new file mode 100644 index 0000000..e649fc1 --- /dev/null +++ b/apidoc/html/folderopen.svg @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/apidoc/html/folderopend.svg b/apidoc/html/folderopend.svg new file mode 100644 index 0000000..5c1999e --- /dev/null +++ b/apidoc/html/folderopend.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/apidoc/html/functions.html b/apidoc/html/functions.html new file mode 100644 index 0000000..4d2d0ba --- /dev/null +++ b/apidoc/html/functions.html @@ -0,0 +1,130 @@ + + + + + + + +smax-clib: Data Fields + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
+
+
+ + + + diff --git a/apidoc/html/functions_vars.html b/apidoc/html/functions_vars.html new file mode 100644 index 0000000..b59d287 --- /dev/null +++ b/apidoc/html/functions_vars.html @@ -0,0 +1,130 @@ + + + + + + + +smax-clib: Data Fields - Variables + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
Here is a list of all documented variables with links to the struct/union documentation for each field:
+
+
+ + + + diff --git a/apidoc/html/globals.html b/apidoc/html/globals.html new file mode 100644 index 0000000..6c1bcab --- /dev/null +++ b/apidoc/html/globals.html @@ -0,0 +1,112 @@ + + + + + + + +smax-clib: Globals + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation:
+ +

- _ -

+
+
+ + + + diff --git a/apidoc/html/globals_defs.html b/apidoc/html/globals_defs.html new file mode 100644 index 0000000..4271482 --- /dev/null +++ b/apidoc/html/globals_defs.html @@ -0,0 +1,159 @@ + + + + + + + +smax-clib: Globals + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
Here is a list of all documented macros with links to the documentation:
+ +

- _ -

+ + +

- m -

+ + +

- r -

+ + +

- s -

    +
  • SMAX_DEFAULT_HOSTNAME : smax.h
  • +
  • SMAX_DEFAULT_MAX_QUEUED : smax.h
  • +
  • SMAX_DEFAULT_PIPELINE_ENABLED : smax.h
  • +
  • SMAX_DIMS : smax.h
  • +
  • SMAX_MSG_DEBUG : smax.h
  • +
  • SMAX_MSG_DETAIL : smax.h
  • +
  • SMAX_MSG_ERROR : smax.h
  • +
  • SMAX_MSG_INFO : smax.h
  • +
  • SMAX_MSG_PROGRESS : smax.h
  • +
  • SMAX_MSG_STATUS : smax.h
  • +
  • SMAX_MSG_WARNING : smax.h
  • +
  • SMAX_ORIGIN_LENGTH : smax.h
  • +
  • SMAX_ORIGINS : smax.h
  • +
  • SMAX_PIPE_READ_TIMEOUT_MILLIS : smax.h
  • +
  • SMAX_READS : smax.h
  • +
  • SMAX_RECONNECT_RETRY_SECONDS : smax.h
  • +
  • SMAX_RESTORE_QUEUE_ON_RECONNECT : smax.h
  • +
  • SMAX_SCRIPTS : smax.h
  • +
  • SMAX_TIMESTAMPS : smax.h
  • +
  • SMAX_TYPES : smax.h
  • +
  • SMAX_UPDATES : smax.h
  • +
  • SMAX_UPDATES_LENGTH : smax.h
  • +
  • SMAX_UPDATES_ROOT : smax.h
  • +
  • SMAX_WRITES : smax.h
  • +
+ + +

- x -

+
+
+ + + + diff --git a/apidoc/html/globals_dup.js b/apidoc/html/globals_dup.js new file mode 100644 index 0000000..43e9ad9 --- /dev/null +++ b/apidoc/html/globals_dup.js @@ -0,0 +1,10 @@ +var globals_dup = +[ + [ "_", "globals.html", null ], + [ "g", "globals_g.html", null ], + [ "h", "globals_h.html", null ], + [ "m", "globals_m.html", null ], + [ "r", "globals_r.html", null ], + [ "s", "globals_s.html", null ], + [ "x", "globals_x.html", null ] +]; \ No newline at end of file diff --git a/apidoc/html/globals_func.html b/apidoc/html/globals_func.html new file mode 100644 index 0000000..9acd896 --- /dev/null +++ b/apidoc/html/globals_func.html @@ -0,0 +1,256 @@ + + + + + + + +smax-clib: Globals + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
Here is a list of all documented functions with links to the documentation:
+ +

- s -

+
+
+ + + + diff --git a/apidoc/html/globals_func.js b/apidoc/html/globals_func.js new file mode 100644 index 0000000..2a665ca --- /dev/null +++ b/apidoc/html/globals_func.js @@ -0,0 +1,5 @@ +var globals_func = +[ + [ "s", "globals_func.html", null ], + [ "x", "globals_func_x.html", null ] +]; \ No newline at end of file diff --git a/apidoc/html/globals_func_x.html b/apidoc/html/globals_func_x.html new file mode 100644 index 0000000..649d75b --- /dev/null +++ b/apidoc/html/globals_func_x.html @@ -0,0 +1,113 @@ + + + + + + + +smax-clib: Globals + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
Here is a list of all documented functions with links to the documentation:
+ +

- x -

+
+
+ + + + diff --git a/apidoc/html/globals_g.html b/apidoc/html/globals_g.html new file mode 100644 index 0000000..a02cd2e --- /dev/null +++ b/apidoc/html/globals_g.html @@ -0,0 +1,112 @@ + + + + + + + +smax-clib: Globals + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation:
+ +

- g -

+
+
+ + + + diff --git a/apidoc/html/globals_h.html b/apidoc/html/globals_h.html new file mode 100644 index 0000000..6d92697 --- /dev/null +++ b/apidoc/html/globals_h.html @@ -0,0 +1,114 @@ + + + + + + + +smax-clib: Globals + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation:
+ +

- h -

+
+
+ + + + diff --git a/apidoc/html/globals_m.html b/apidoc/html/globals_m.html new file mode 100644 index 0000000..fee2332 --- /dev/null +++ b/apidoc/html/globals_m.html @@ -0,0 +1,116 @@ + + + + + + + +smax-clib: Globals + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation:
+ +

- m -

+
+
+ + + + diff --git a/apidoc/html/globals_r.html b/apidoc/html/globals_r.html new file mode 100644 index 0000000..adf12d4 --- /dev/null +++ b/apidoc/html/globals_r.html @@ -0,0 +1,112 @@ + + + + + + + +smax-clib: Globals + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation:
+ +

- r -

+
+
+ + + + diff --git a/apidoc/html/globals_s.html b/apidoc/html/globals_s.html new file mode 100644 index 0000000..3a24cca --- /dev/null +++ b/apidoc/html/globals_s.html @@ -0,0 +1,280 @@ + + + + + + + +smax-clib: Globals + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation:
+ +

- s -

+
+
+ + + + diff --git a/apidoc/html/globals_vars.html b/apidoc/html/globals_vars.html new file mode 100644 index 0000000..3bfe059 --- /dev/null +++ b/apidoc/html/globals_vars.html @@ -0,0 +1,113 @@ + + + + + + + +smax-clib: Globals + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
Here is a list of all documented variables with links to the documentation:
+
+
+ + + + diff --git a/apidoc/html/globals_x.html b/apidoc/html/globals_x.html new file mode 100644 index 0000000..2c2b6e4 --- /dev/null +++ b/apidoc/html/globals_x.html @@ -0,0 +1,114 @@ + + + + + + + +smax-clib: Globals + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation:
+ +

- x -

+
+
+ + + + diff --git a/apidoc/html/index.html b/apidoc/html/index.html new file mode 100644 index 0000000..66285d3 --- /dev/null +++ b/apidoc/html/index.html @@ -0,0 +1,564 @@ + + + + + + + +smax-clib: smax-clib + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
smax-clib
+
+
+

Author: Attila Kovacs

+

Last Updated: 14 September 2024

+

+Table of Contents

+ +
+

+

+Introduction

+

The SMA information eXchange (SMA-X) is a high performance and versatile data sharing platform for distributed software systems. It is built around a central Redis database, and provides atomic access to structured data, including specific branches and/or leaf nodes, with associated metadadata.

+

SMA-X consists of a set of server-side LUA scripts that run on Redis (or one of its forks / clones such as Valkey or Dragonfly); a set of libraries to interface client applications; and a set of command-line tools build with them. Currently we provide client libraries for C/C++ and Python 3. We may provide Java and/or Rust client libraries too in the future.

+
+

+

+Prerequisites

+

The SMA-X C/C++ library has a build and runtime dependency on the xchange and RedisX libraries also available at the Smithsonian Github repositories:

+ +

Additionally, to configure your Redis (or Valkey / Dragonfly) servers for SMA-X, you will need the Smithsonian/smax-server repo also.

+
+

+

+Building the SMA-X C library

+

The smax-clib library can be built either as a shared (libsmax.so[.1]) and as a static (libsmax.a) library, depending on what suits your needs best.

+

You can configure the build, either by editing config.mk or else by defining the relevant environment variables prior to invoking make. The following build variables can be configured:

+
    +
  • XCHANGE: the root of the location where the Smithsonian/xchange library is installed. It expects to find xchange.h under $(XCHANGE)/include and libxchange.so under $(XCHANGE)/lib or else in the default LD_LIBRARY_PATH.
  • +
  • REDISX: the root of the location where the Smithsonian/redisx library is installed. It expects to find redisx.h under $(REDISX)/include and libredisx.so under $(REDISX)/lib or else in the default LD_LIBRARY_PATH.
  • +
  • CC: The C compiler to use (default: gcc).
  • +
  • CPPFLAGS: C pre-processor flags, such as externally defined compiler constants.
  • +
  • CFLAGS: Flags to pass onto the C compiler (default: -Os -Wall). Note, -Iinclude will be added automatically.
  • +
  • LDFLAGS: Linker flags (default is -lm). Note, -lredisx -lxchange will be added automatically.
  • +
  • BUILD_MODE: You can set it to debug to enable debugging features: it will initialize the global xDebug variable to TRUE and add -g to CFLAGS.
  • +
  • CHECKEXTRA: Extra options to pass to cppcheck for the make check target
  • +
+

After configuring, you can simply run make, which will build the shared (lib/libsmax.so[.1]) and static (lib/libsmax.a) libraries, local HTML documentation (provided doxygen is available), and performs static analysis via the check target. Or, you may build just the components you are interested in, by specifying the desired make target(s). (You can use make help to get a summary of the available make targets).

+
+

+

+Initial configuration

+

Bu default, the library assumes that the Redis server used for SMA-X runs on a machine called smax (e.g. you may assign smax to the IP address in /etc/hosts), and that the Redis is on the default port 6379/tcp. However, you can configure to use a specific host and/or an alternative Redis port number to use instead.

+
smaxSetServer("my-smax.example.com", 7033);
+
int smaxSetServer(const char *host, int port)
Definition smax.c:109
+

Also, while SMA-X will normally run on database index 0, you can also specify a different database number to use. E.g.:

+
+
int smaxSetDB(int idx)
Definition smax.c:165
+

(Note, you can switch the database later also, but beware that if you have an active subscription client open, you cannot switch that client until the subscriptions are terminated.)

+

You can also set up the authentication credentials for using the SMA-X database on the Redis server:

+
smaxSetUser("johndoe");
+
smaxSetPassword("mySecretPassword);
+

And finally, you can select the option to automatically try reconnect to the SMA-X server in case of lost connection or network errors (and keep track of changes locally until then):

+
+
void smaxSetResilient(boolean value)
Definition smax-resilient.c:62
+

+

+

+Connecting to / disconnecting from SMA-X

+

Once you have configured the connection parameters, you can connec to the server by:

+
int status = smaxConnect();
+
if(status < 0) {
+
// Oops, we could not connect to the server
+
...
+
}
+
int smaxConnect()
Definition smax.c:418
+

And, when you are done, you should disconnect with:

+
+
int smaxDisconnect()
Definition smax.c:503
+

+

+Connection / disconnection hooks

+

The user of the smax-clib library might want to know when connections to the SMA-X server are established, or when disconnections happen, and may want to perform some configuration or clean-up accordingly. For this reason, the library provides support for connection 'hooks' – that is custom functions that are called in the even of connecting to or disconnecting from a Redis server.

+

Here is an example of a connection hook, which simply prints a message about the connection to the console.

+
void my_connect_hook() {
+
printf("Connected to SMA-X server\n");
+
}
+

And, it can be activated prior to the smaxConnect() call.

+
smaxAddConnectHook(my_connect_hook);
+
int smaxAddConnectHook(void(*setupCall)(void))
Definition smax.c:553
+

The same goes for disconnect hooks, using smaxAddDisconnectHook() instead.

+
+

+

+Sharing and pulling data

+ +

+

+The basics

+

For SMA-X we use the terms sharing and pulling, instead of the more generic get/set terminology. The intention is to make programmers conscious of the fact that the transactions are not some local access to memory, but that they involve networking, and as such may be subject to unpredictable latencies, network outages, or other errors.

+

At the lowest level, the library provides two functions accordingly: smaxShare() and smaxPull(), either to send local data to store in SMA-X, or to retrieve data from SMA-X for local use, respectively. There are higher-level functions too, which build on these, providing a simpler API for specific data types, or extra features, such as lazy or pipelined pulls. These will be discussed in the sections below. But, before that, let's look into the basics of how data is handled between you machine local data that you use in your C/C++ application and its machine-independent representation in SMA-X.

+

Here is an example for a generic sharing of a double[] array from C/C++:

+
double data[8] = ... // your local data
+
+
// Share (send) this data to SMA-X as "system:subsystem:some_data"
+
int status = smaxShare("system:subsystem", "some_data", X_DOUBLE, 8);
+
if(status < 0) {
+
// Ooops, that did not work...
+
...
+
}
+
int smaxShare(const char *table, const char *key, const void *value, XType type, int count)
Definition smax.c:708
+

Pulling data back from SMA-X works similarly, e.g.:

+
double data[4][2] = ... // buffer in which we will receive data
+
XMeta meta; // (optional) metadata we can obtain
+
+
// Retrieve 'data' from the SMA-X "system:subsystem:some_data", as 8 doubles
+
int status = smaxPull("system:subsystem", "some_data", X_DOUBLE, 8, data, &meta);
+
if(status < 0) {
+
// Oops, something went wrong...
+
return;
+
}
+
int smaxPull(const char *table, const char *key, XType type, int count, void *value, XMeta *meta)
Definition smax.c:637
+
SMA-X standard metadata.
Definition smax.h:132
+

The metadata argument is optional, and can be NULL if not required.

+

+

+Standard metadata

+

For every variable (structure or leaf node) in SMA-X there is also a set of essential metadata that is stored in the Redis database, which describe the data themselves, such as the native type (at the origin); the size as stored in Redis; the array dimension and shape; the host (and program) which provided the data; the time it was last updated; and a serial number.

+

The user of the library has the option to retrieve metadata together with the actual data, and thus gain access to this information. The header file smax.h defines the Xmeta type as:

+
typedef struct XMeta {
+
int status; // Error code or X_SUCCESS.
+
XType storeType; // Type of variable as stored.
+
int storeDim; // Dimensionality of the data as stored.
+
int storeSizes[X_MAX_DIMS]; // Sizes along each dimension of the data as stored.
+
int storeBytes; // Total number of bytes stored.
+
char origin[SMAX_ORIGIN_LENGTH]; // Host name that last modified.
+
struct timespec timestamp; // Timestamp of the last modification.
+
int serial; // Number of times the variable was updated.
+ +
#define SMAX_ORIGIN_LENGTH
(bytes) Maximum length of 'origin' meatdata, including termination.
Definition smax.h:84
+
char origin[SMAX_ORIGIN_LENGTH]
Host name that last modified.
Definition smax.h:138
+
int storeDim
Dimensionality of the data as stored.
Definition smax.h:135
+
struct timespec timestamp
Timestamp of the last modification.
Definition smax.h:139
+
int serial
Number of times the variable was updated.
Definition smax.h:140
+
int status
Error code or X_SUCCESS.
Definition smax.h:133
+
int storeBytes
Total number of bytes stored.
Definition smax.h:137
+
XType storeType
Type of variable as stored.
Definition smax.h:134
+
int storeSizes[X_MAX_DIMS]
Sizes along each dimension of the data as stored.
Definition smax.h:136
+

+

+Flexible types and sizes

+

One nifty feature of the library is that as a consumer you need not be too concerned about what type or size of data the producer provides. The program that produces the data may sometimes change, for example from writing 32-bit floating point types to a 64-bit floating point types. Also while it produced data for say 10 units before (as an array of 10), now it might report for just 9, or perhaps it now reports for 12.

+

The point is that if your consumer application was written to expect ten 32-bit floating floating point values, it can get that even if the producer changed the exact type or element count since you have written your client. The library will simply apply the necessaty type conversion automatically, and then truncate, or else pad (with zeroes), the data as necessary to get what you want.

+

The type conversion can be both widening or narrowing. Strings and numerical values can be converted to one another through the expected string representation of numbers and vice versa. Boolean true values are treated equivalently to a numerical value of 1 and all non-zero numerical values will convert to boolean true.

+

And, if you are concerned about the actual type or size (or shape) of the data stored, you have the option to inspect the metadata, and make decisions based on it. Otherwise, the library will just take care of giving you the available data in the format you expect.

+

+

+Scalar quantities

+

Often enough we deal with scalar quantities (not arrays), such as a single number, boolean value, or a string (yes, we treat strings i.e., char *, as a scalar too!).

+

Here are some examples of sharing scalars to SMA-X. Easy-peasy:

+
int status;
+
+
// Put a boolean value into SMA-X
+
status = smaxShareBoolean("system:subsystem", "is_online", TRUE);
+
+
// Put an integer value into SMA-X
+
status = smaxShareInt("system:subsystem", "some_int_value", 1012);
+
+
// Put a floating-point value into SMA-X
+
status = smaxShareDouble("system:subsystem", "some_value", -3.4032e-11);
+
+
// Put a string value into SMA-X
+
status = smaxShareString("system:subsystem", "name", "blah-blah");
+
int smaxShareBoolean(const char *table, const char *key, boolean value)
Definition smax-easy.c:430
+
int smaxShareString(const char *table, const char *key, const char *sValue)
Definition smax-easy.c:463
+
int smaxShareDouble(const char *table, const char *key, double value)
Definition smax-easy.c:447
+
int smaxShareInt(const char *table, const char *key, long long value)
Definition smax-easy.c:397
+

Or pulling them from SMA-X:

+
// Retrieve "system:subsystem:is_online" as a boolean, defaulting to FALSE
+
boolean isTrue = smaxPullBoolean("system:subsystem", "is_online", FALSE);
+
+
// Retrieve "system:subsystem:some_int_value" as an int, with a default value of -1
+
int c = smaxPullInt("system:subsystem", "some_int_value", -1);
+
+
// Retrieve "system:subsystem:some_value" as a double (or else NAN if cannot).
+
double value = smaxPullDouble("system:subsystem", "some_value");
+
if(!isnan(value)) { // check for NAN if need be
+
...
+
}
+
+
// Retrieve "system:subsystem:name" as a 0-terminated C string (or NULL if cannot).
+
char *str = smaxPullDouble("system:subsystem", "name");
+
if(str != NULL) { // check for NULL
+
...
+
}
+
+
...
+
+
// Once the pulled string is no longer needed, destroy it.
+
free(str)
+
int smaxPullInt(const char *table, const char *key, int defaultValue)
Definition smax-easy.c:324
+
double smaxPullDouble(const char *table, const char *key)
Definition smax-easy.c:362
+

+

+Arrays

+

The generic smaxShare() function readily handles 1D arrays, and the smaxPull() handles native (monolithic) arrays of all types (e.g. double[][], or boolean[][][]). However, you may want to share multidimensional arrays, noting their specific shapes, or else pull array data for which you may not know in advance what size (or shape) of the storage needed locally for the values stored in SMA-X for some variable. For these reasons, the library provides a set of functions to make the handling of arrays a simpler too.

+

Let's begin with sharing multi-dimensional arrays. Instead of smaxShare(), you can use smaxShareArray() which allows you to define the multi-dimensional shape of the data beyond just the number of elements stored. E.g.:

+
float data[4][2] = ... // Your local 2D data array
+
int shape[] = { 4, 2 }; // The array shape as stored in SMA-X
+
+
int status = smaxShareArray("system:subsystem", "my_2d_array", X_FLOAT, 2, shape);
+
if (status < 0) {
+
// Oops, did not work...
+
...
+
}
+
int smaxShareArray(const char *table, const char *key, const void *ptr, XType type, int ndim, const int *sizes)
Definition smax.c:735
+

Note, that the dimensions of how the data is stored in SMA-X is determined solely by the '2' dimensions specified as the 4th argument and the corresponding 2 elements in the shape array. The data could have been any pointer to an array of floats containing at least the required number of element (8 in the example above).

+

For 1D arrays, you have some convenience methods for sharing specific types. These can be convenient because they eliminate one potential source of bugs, where the type argument to smaxShare() does not match the pointer type of the data. Using, say, smaxShareFloats() instead to share a 1D floating-point array instead of the generic smaxShare() will allow the compiler to check and warn you if the data array is not the float * type. E.g.:

+
float *data = ... // pointer to a one or higher-dimensional C array of floats.
+
+
// Send N elements from data to SMA-X as "system:subsystem:my_array"
+
int status = smaxShareFloats("system:subsystem", "my_array", data, N);
+
if (status < 0) {
+
// Oops, did not work...
+
...
+
}
+
int smaxShareFloats(const char *table, const char *key, const float *values, int n)
Definition smax-easy.c:580
+

Similar functions are available for every built-in type (primitives, plus strings and booleans). For pulling arrays without knowing a-priori the element count or shape, there are also convenience functions, such as:

+
XMeta meta; // (optional) we'll return the metadata in this
+
int status; // we'll return the status in this
+
+
// Get whatever data is in "system:subsystem:my_array" as doubles.
+
double *data = smaxPullDoubles("system:subsystem", "my_array", &meta, &status);
+
if(status < 0) {
+
// Oops, we got an error
+
}
+
if(data == NULL) {
+
// Oops the data is NULL
+
}
+
+
...
+
+
// When done using the data we obtained, destroy it.
+
free(data);
+
double * smaxPullDoubles(const char *table, const char *key, XMeta *meta, int *n)
Definition smax-easy.c:209
+

As illustrated, the above will return a dynamically allocated array with the required size to hold the data, and the size and shape of the data is returned in the metadata that was also supplied with the call. After using the returned data (and ensuring that it is not NULL), you should always call free() on it to avoid memory leaks in your application.

+

+

+Structures / substructures...

+

You can share entire data structures, represented by an appropriate XStructure type (see the xchange library for a description and usage):

+
XStructure s = ... // The structured data you have prepared locally.
+
+
int status = smaxShareStruct("syste:subsystem", &s);
+
if(status < 0) {
+
// Oops, something did not work
+
...
+
}
+
int smaxShareStruct(const char *id, const XStructure *s)
Definition smax.c:866
+

Or, you can read a structure, including all embedded substructures in it, with smaxPullStruct():

+
XMeta meta;
+
int nElements;
+
+
XStructure *s = smaxPullStruct("system", "subsystem", &meta, &n);
+
if(n < 0) {
+
// Oops there was an error...
+
return;
+
}
+
+
double value = smaxGetDoubleField(s, "some_value", 0.0);
+
+
...
+
+
// Once the pulled structure is no longer needed, destroy it...
+
xDestroyStruct(s);
+
XStructure * smaxPullStruct(const char *id, XMeta *meta, int *status)
Definition smax-easy.c:68
+
double smaxGetDoubleField(const XStructure *s, const char *name, double defaultValue)
Definition smax-easy.c:825
+

Note, that the structure returned by smaxPullStruct() is in the serialized format of SMA-X. That is, all leaf nodes are stored as strings, just as they appear in the Redis database. Hence, we used the smaxGet...Field() methods above to deserialize the leaf nodes as needed on demand. If you want to use the methods of xchange to access the structure, you will need to convert to binary format first, using smax2xStruct(XStructure *).

+

Note also, that pulling large structures can be an expensive operation on the Redis server, and may block the server for longer than usual periods, causing latencies for other programs that use SMA-X. It's best to use this method for smallish structures only (with, say, a hundred or so or fewer leaf nodes).

+
+

+

+Lazy pulling (high-frequency queries)

+

What happens if you need the data frequently? Do you pound on the database at some high-frequency? No, you probably no not want to do that, especially if the data you need is not necessaily changing fast. There is no point on wasting network bandwidth only to return the same values again and again. This is where 'lazy' pulling excels.

+

From the caller's perspective lazy pulling works just like regular SMA-X pulls, e.g.:

+
int data[10][4][2];
+
int sizes[] = { 10, 4, 2 };
+
XMeta meta;
+
+
int status = smaxLazyPull("some_table", "some_data", X_INT, 3, sizes, data, &meta);
+
int smaxLazyPull(const char *table, const char *key, XType type, int count, void *value, XMeta *meta)
Definition smax-lazy.c:439
+

or

+
int status = smaxLazyPullDouble("some_table", "some_var");
+
double smaxLazyPullDouble(const char *table, const char *key)
Definition smax-lazy.c:487
+

But, under the hood, it does something different. The first time a new variable is lazy pulled it is fetched from the Redis database just like a regular pull. But, it also will cache the value, and watch for update notifications from the SMA-X server. Thus, as long as no update notification is received, successive calls will simply return the locally cached value. This can save big on network usage, and also provides orders of magnitude faster access so long as the variable remains unchanged.

+

When the vatiable is updated in SMA-X, our client library will be notified, and one of two things can happen:

+
    +
  1. it invalidates the cache, so that the next lazy pull will again work just like a regular pull, fetching the updated value from SMA-X on demand. And again the library will cache that value and watch for notifications for the next update. Or,
  2. +
  3. it will trigger a background process to update the cached value in the background with a pipelined (high-throughput) pull. However, until the new value is actually fetched, it will return the previously cached value promptly.
  4. +
+

The choice between the two is yours, and you can control which suits your need best. The default behavior for lazy pulls is (1), but you may call smaxLazyCache() after the first pull of a variable, to indicate that you want to enable background cache updates (2) for it. The advantage of (1) is that it will never serve you outdated data even if there are significant network latencies – but you may have to wait a little to fetch updates. On the other hand (2) will always provide a recent value with effectively no latency, but this value may be outdated if there are delays on the network updating the cache. The difference is typically at the micro-seconds level on a local LAN. However, (2) may be preferable when you need to access SMA-X data from timing critical code blocks, where it is more important to ensure that the value is returned quickly, rather than whether it is a millisecond too old or not.

+

In either case, when you are done using lazy variables, you should let the library know that it no longer needs to watch updates for these, by calling either smaxLazyEnd() on specific variables, or else smaxLazyFlush() to stop watching updates for all lazy variables. (A successive lazy pull will automatically start watching for updates again, in case you wish to re-enable).

+
// Lazy pull a bunch of data (typically in a loop).
+
for(...) {
+
smaxLazyPull("some_table", "some_var", ...);
+
smaxLaxyPull(...);
+
...
+
}
+
+
// Once we do not need "some_table:some_var" any more:
+
smaxLazyEnd("some_table", "some_var");
+
+
...
+
+
// And to stop lazy accessing all
+
smaxLazyFlush();
+
int smaxLazyEnd(const char *table, const char *key)
Definition smax-lazy.c:597
+

+

+

+Pipelined pulling (high volume queries)

+ +

The regular pulling of data from SMA-X requires a separate round-trip for each and every request. That is, successive pulls are sent only after the responses from the prior pull has been received. A lot of the time is spent on waiting for responses to come back. With round trip times in the 100 μs range, this means that this method of fetching data from SMA-X is suitable for obtaining at most a a few thousand values per second.

+

However, sometimes you want to get access to a large number of values faster. This is what pipelined pulling is for. In pipelined mode, a batch of pull requests are sent to the SMA-X Redis server in quick succession, without waiting for responses. The values, when received are processed by a dedicated background thread. And, the user has an option of either waiting until all data is collected, or ask for as callback when the data is ready.

+

Again it works similarly to the basic pulling, except that you submit your pull request to a queue with smaxQueue(). For example:

+
double d; // A value we will fill
+
XMeta meta; // (optional) metadata to fill (for the above value).
+
+
int status = smaxQueue("some_table", "some_var", X_DOUBLE, 1, &d, &meta);
+
int smaxQueue(const char *table, const char *key, XType type, int count, void *value, XMeta *meta)
Definition smax-queue.c:480
+

Pipelined (batched) pulls have dramatic effects on performance. Rather than being limited by round-trip times, you will be limited by the performance of the Redis server itself (or the network bandwidth on some older infrastructure). As such, instead of thousand of queries per second, you can pull 2-3 orders of magnitude more in a given time, with hudreds of thousands to even millions of pull per second this way.

+

+

+Synchronization points and waiting

+

After you have submitted a batch of pull request to the queue, you can create a synchronization point as:

+
+
XSyncPoint * smaxCreateSyncPoint()
Definition smax-queue.c:67
+
Synchronization point that can be waited upon when queueing pipelined pulls.
Definition smax.h:94
+

A synchronization point is a marker in the queue that we can wait on. After the synchronization point is created, you can sumbit more pull request to the same queue (e.g. for another processing block), or do some other things for a bit (since it will take at least some microseconds before the data is ready). Then, when ready you can wait on the specific synchronization point to ensure that data submitted prior to its creation is delivered from SMA-X:

+
// Wait for data submitted prior to syncPoint to be ready, or time out after 1000 ms.
+
int status = smaxSync(syncPoint, 1000);
+
+
// Destroy the synchronization point if we no longer need it.
+
xDestroySyncPoint(syncPoint);
+
+
// Check return status...
+
if(status == X_TIMEOUT) {
+
// We timed out
+
...
+
}
+
else if(status < 0) {
+
// Some other error
+
...
+
}
+
int smaxSync(XSyncPoint *sync, int timeoutMillis)
Definition smax-queue.c:247
+

+

+Callbacks

+

The alternative to synchronization points and waiting, is to provide a callback function, which will process your data as soon as it is available, e.g.:

+
void my_pull_processor(void *arg) {
+
// Say, we expect a string tag passed along to identify what we need to process...
+
char *tag = (char *) arg;
+
+
// Do what we need to do...
+
...
+
}
+

Then submit this callback routine to the queue after the set of variables it requires with:

+
// We'll call my_pull_processor, with the argument "some_tag", when prior data has arrived.
+
smaxQueueCallback(my_pull_processor, "some_tag");
+
int smaxQueueCallback(void(*f)(void *), void *arg)
Definition smax-queue.c:141
+

+

+Finishing up

+

If you might still have some pending pipelined pulls that have not received responses yet, you may want to wait until all previously sumbitted requests have been collected. You can do that with:

+
// Wait for up to 3000 ms for all pipelined pulls to collect responses from SMA-X.
+
int status = smaxWaitQueueComplete(3000);
+
+
// Check return status...
+
if(status == X_TIMEOUT) {
+
// We timed out
+
...
+
}
+
else if(status < 0) {
+
// Some other error
+
...
+
}
+
int smaxWaitQueueComplete(int timeoutMillis)
Definition smax-queue.c:322
+

+

+

+Custom notifications and update handling

+

+Monitoring updates

+

+Waiting for updates

+

+Status / error messages

+
+

+

+Optional metadata

+

+Descriptions

+

+Coordinate Systems

+

+Physical units

+

+Coordinate systems

+
+

+

+Error handling

+

The principal error handling of the library is an extension of that of xchange, with further error codes defined in smax.h and redisx.h. The functions that return an error status (either directly, or into the integer designated by a pointer argument), can be inspected by smaxErrorDescription(), e.g.:

+
int status = smaxShare(...);
+
if (status != X_SUCCESS) {
+
// Ooops, something went wrong...
+
fprintf(stderr, "WARNING! set value: %s", smaxErrorDescription(status));
+
...
+
}
+
const char * smaxErrorDescription(int code)
Definition smax-util.c:257
+

+

+

+Debug support

+

You can enable verbose output of the library with smaxSetVerbose(boolean). When enabled, it will produce status messages to stderrso you can follow what's going on. In addition (or alternatively), you can enable debug messages with xSetDebug(boolean). When enabled, all errors encountered by the library (such as invalid arguments passed) will be printed to stderr, including call traces, so you can walk back to see where the error may have originated from. (You can also enable debug messages by default by defining the DEBUG constant for the compiler, e.g. by adding -DDEBUG to CFLAGS prior to calling make).

+

For helping to debug your application, the xchange library provides two macros: xvprintf() and xdprintf(), for printing verbose and debug messages to stderr. Both work just like printf(), but they are conditional on verbosity being enabled via xSetVerbose(boolean) and xSetDebug(boolean), respectively. Applications using this library may use these macros to produce their own verbose and/or debugging outputs conditional on the same global settings.

+
+

+

+Future plans

+

Some obvious ways the library could evolve and grow in the not too distant future:

+
    +
  • Automated regression testing and coverage tracking.
  • +
+

If you have an idea for a must have feature, please let me (Attila) know. Pull requests, for new features or fixes to existing ones, are especially welcome!

+
+

Copyright (C) 2024 Attila Kovács

+
+ +
+
+ + + + diff --git a/apidoc/html/jquery.js b/apidoc/html/jquery.js new file mode 100644 index 0000000..1dffb65 --- /dev/null +++ b/apidoc/html/jquery.js @@ -0,0 +1,34 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0",options:{classes:{},disabled:!1,create:null},_createWidget:function(t,e){e=y(e||this.defaultElement||this)[0],this.element=y(e),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=y(),this.hoverable=y(),this.focusable=y(),this.classesElementLookup={},e!==this&&(y.data(e,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===e&&this.destroy()}}),this.document=y(e.style?e.ownerDocument:e.document||e),this.window=y(this.document[0].defaultView||this.document[0].parentWindow)),this.options=y.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:y.noop,_create:y.noop,_init:y.noop,destroy:function(){var i=this;this._destroy(),y.each(this.classesElementLookup,function(t,e){i._removeClass(e,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:y.noop,widget:function(){return this.element},option:function(t,e){var i,s,n,o=t;if(0===arguments.length)return y.widget.extend({},this.options);if("string"==typeof t)if(o={},t=(i=t.split(".")).shift(),i.length){for(s=o[t]=y.widget.extend({},this.options[t]),n=0;n
"),i=e.children()[0];return y("body").append(e),t=i.offsetWidth,e.css("overflow","scroll"),t===(i=i.offsetWidth)&&(i=e[0].clientWidth),e.remove(),s=t-i},getScrollInfo:function(t){var e=t.isWindow||t.isDocument?"":t.element.css("overflow-x"),i=t.isWindow||t.isDocument?"":t.element.css("overflow-y"),e="scroll"===e||"auto"===e&&t.widthx(D(s),D(n))?o.important="horizontal":o.important="vertical",p.using.call(this,t,o)}),h.offset(y.extend(l,{using:t}))})},y.ui.position={fit:{left:function(t,e){var i=e.within,s=i.isWindow?i.scrollLeft:i.offset.left,n=i.width,o=t.left-e.collisionPosition.marginLeft,h=s-o,a=o+e.collisionWidth-n-s;e.collisionWidth>n?0n?0=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),y.ui.plugin={add:function(t,e,i){var s,n=y.ui[t].prototype;for(s in i)n.plugins[s]=n.plugins[s]||[],n.plugins[s].push([e,i[s]])},call:function(t,e,i,s){var n,o=t.plugins[e];if(o&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(n=0;n").css({overflow:"hidden",position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,t={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(t),this.originalElement.css("margin",0),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css(t),this._proportionallyResize()),this._setupHandles(),e.autoHide&&y(this.element).on("mouseenter",function(){e.disabled||(i._removeClass("ui-resizable-autohide"),i._handles.show())}).on("mouseleave",function(){e.disabled||i.resizing||(i._addClass("ui-resizable-autohide"),i._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy(),this._addedHandles.remove();function t(t){y(t).removeData("resizable").removeData("ui-resizable").off(".resizable")}var e;return this.elementIsWrapper&&(t(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),t(this.originalElement),this},_setOption:function(t,e){switch(this._super(t,e),t){case"handles":this._removeHandles(),this._setupHandles();break;case"aspectRatio":this._aspectRatio=!!e}},_setupHandles:function(){var t,e,i,s,n,o=this.options,h=this;if(this.handles=o.handles||(y(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=y(),this._addedHandles=y(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),i=this.handles.split(","),this.handles={},e=0;e"),this._addClass(n,"ui-resizable-handle "+s),n.css({zIndex:o.zIndex}),this.handles[t]=".ui-resizable-"+t,this.element.children(this.handles[t]).length||(this.element.append(n),this._addedHandles=this._addedHandles.add(n));this._renderAxis=function(t){var e,i,s;for(e in t=t||this.element,this.handles)this.handles[e].constructor===String?this.handles[e]=this.element.children(this.handles[e]).first().show():(this.handles[e].jquery||this.handles[e].nodeType)&&(this.handles[e]=y(this.handles[e]),this._on(this.handles[e],{mousedown:h._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(i=y(this.handles[e],this.element),s=/sw|ne|nw|se|n|s/.test(e)?i.outerHeight():i.outerWidth(),i=["padding",/ne|nw|n/.test(e)?"Top":/se|sw|s/.test(e)?"Bottom":/^e$/.test(e)?"Right":"Left"].join(""),t.css(i,s),this._proportionallyResize()),this._handles=this._handles.add(this.handles[e])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){h.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),h.axis=n&&n[1]?n[1]:"se")}),o.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._addedHandles.remove()},_mouseCapture:function(t){var e,i,s=!1;for(e in this.handles)(i=y(this.handles[e])[0])!==t.target&&!y.contains(i,t.target)||(s=!0);return!this.options.disabled&&s},_mouseStart:function(t){var e,i,s=this.options,n=this.element;return this.resizing=!0,this._renderProxy(),e=this._num(this.helper.css("left")),i=this._num(this.helper.css("top")),s.containment&&(e+=y(s.containment).scrollLeft()||0,i+=y(s.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:e,top:i},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:n.width(),height:n.height()},this.originalSize=this._helper?{width:n.outerWidth(),height:n.outerHeight()}:{width:n.width(),height:n.height()},this.sizeDiff={width:n.outerWidth()-n.width(),height:n.outerHeight()-n.height()},this.originalPosition={left:e,top:i},this.originalMousePosition={left:t.pageX,top:t.pageY},this.aspectRatio="number"==typeof s.aspectRatio?s.aspectRatio:this.originalSize.width/this.originalSize.height||1,s=y(".ui-resizable-"+this.axis).css("cursor"),y("body").css("cursor","auto"===s?this.axis+"-resize":s),this._addClass("ui-resizable-resizing"),this._propagate("start",t),!0},_mouseDrag:function(t){var e=this.originalMousePosition,i=this.axis,s=t.pageX-e.left||0,e=t.pageY-e.top||0,i=this._change[i];return this._updatePrevProperties(),i&&(e=i.apply(this,[t,s,e]),this._updateVirtualBoundaries(t.shiftKey),(this._aspectRatio||t.shiftKey)&&(e=this._updateRatio(e,t)),e=this._respectSize(e,t),this._updateCache(e),this._propagate("resize",t),e=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),y.isEmptyObject(e)||(this._updatePrevProperties(),this._trigger("resize",t,this.ui()),this._applyChanges())),!1},_mouseStop:function(t){this.resizing=!1;var e,i,s,n=this.options,o=this;return this._helper&&(s=(e=(i=this._proportionallyResizeElements).length&&/textarea/i.test(i[0].nodeName))&&this._hasScroll(i[0],"left")?0:o.sizeDiff.height,i=e?0:o.sizeDiff.width,e={width:o.helper.width()-i,height:o.helper.height()-s},i=parseFloat(o.element.css("left"))+(o.position.left-o.originalPosition.left)||null,s=parseFloat(o.element.css("top"))+(o.position.top-o.originalPosition.top)||null,n.animate||this.element.css(y.extend(e,{top:s,left:i})),o.helper.height(o.size.height),o.helper.width(o.size.width),this._helper&&!n.animate&&this._proportionallyResize()),y("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s=this.options,n={minWidth:this._isNumber(s.minWidth)?s.minWidth:0,maxWidth:this._isNumber(s.maxWidth)?s.maxWidth:1/0,minHeight:this._isNumber(s.minHeight)?s.minHeight:0,maxHeight:this._isNumber(s.maxHeight)?s.maxHeight:1/0};(this._aspectRatio||t)&&(e=n.minHeight*this.aspectRatio,i=n.minWidth/this.aspectRatio,s=n.maxHeight*this.aspectRatio,t=n.maxWidth/this.aspectRatio,e>n.minWidth&&(n.minWidth=e),i>n.minHeight&&(n.minHeight=i),st.width,h=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,a=this.originalPosition.left+this.originalSize.width,r=this.originalPosition.top+this.originalSize.height,l=/sw|nw|w/.test(i),i=/nw|ne|n/.test(i);return o&&(t.width=e.minWidth),h&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),o&&l&&(t.left=a-e.minWidth),s&&l&&(t.left=a-e.maxWidth),h&&i&&(t.top=r-e.minHeight),n&&i&&(t.top=r-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];e<4;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(n[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;e").css({overflow:"hidden"}),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++e.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize;return{left:this.originalPosition.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize;return{top:this.originalPosition.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(t,e,i){return y.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,e,i]))},sw:function(t,e,i){return y.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,e,i]))},ne:function(t,e,i){return y.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,e,i]))},nw:function(t,e,i){return y.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,e,i]))}},_propagate:function(t,e){y.ui.plugin.call(this,t,[e,this.ui()]),"resize"!==t&&this._trigger(t,e,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),y.ui.plugin.add("resizable","animate",{stop:function(e){var i=y(this).resizable("instance"),t=i.options,s=i._proportionallyResizeElements,n=s.length&&/textarea/i.test(s[0].nodeName),o=n&&i._hasScroll(s[0],"left")?0:i.sizeDiff.height,h=n?0:i.sizeDiff.width,n={width:i.size.width-h,height:i.size.height-o},h=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left)||null,o=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(y.extend(n,o&&h?{top:o,left:h}:{}),{duration:t.animateDuration,easing:t.animateEasing,step:function(){var t={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};s&&s.length&&y(s[0]).css({width:t.width,height:t.height}),i._updateCache(t),i._propagate("resize",e)}})}}),y.ui.plugin.add("resizable","containment",{start:function(){var i,s,n=y(this).resizable("instance"),t=n.options,e=n.element,o=t.containment,h=o instanceof y?o.get(0):/parent/.test(o)?e.parent().get(0):o;h&&(n.containerElement=y(h),/document/.test(o)||o===document?(n.containerOffset={left:0,top:0},n.containerPosition={left:0,top:0},n.parentData={element:y(document),left:0,top:0,width:y(document).width(),height:y(document).height()||document.body.parentNode.scrollHeight}):(i=y(h),s=[],y(["Top","Right","Left","Bottom"]).each(function(t,e){s[t]=n._num(i.css("padding"+e))}),n.containerOffset=i.offset(),n.containerPosition=i.position(),n.containerSize={height:i.innerHeight()-s[3],width:i.innerWidth()-s[1]},t=n.containerOffset,e=n.containerSize.height,o=n.containerSize.width,o=n._hasScroll(h,"left")?h.scrollWidth:o,e=n._hasScroll(h)?h.scrollHeight:e,n.parentData={element:h,left:t.left,top:t.top,width:o,height:e}))},resize:function(t){var e=y(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.position,o=e._aspectRatio||t.shiftKey,h={top:0,left:0},a=e.containerElement,t=!0;a[0]!==document&&/static/.test(a.css("position"))&&(h=s),n.left<(e._helper?s.left:0)&&(e.size.width=e.size.width+(e._helper?e.position.left-s.left:e.position.left-h.left),o&&(e.size.height=e.size.width/e.aspectRatio,t=!1),e.position.left=i.helper?s.left:0),n.top<(e._helper?s.top:0)&&(e.size.height=e.size.height+(e._helper?e.position.top-s.top:e.position.top),o&&(e.size.width=e.size.height*e.aspectRatio,t=!1),e.position.top=e._helper?s.top:0),i=e.containerElement.get(0)===e.element.parent().get(0),n=/relative|absolute/.test(e.containerElement.css("position")),i&&n?(e.offset.left=e.parentData.left+e.position.left,e.offset.top=e.parentData.top+e.position.top):(e.offset.left=e.element.offset().left,e.offset.top=e.element.offset().top),n=Math.abs(e.sizeDiff.width+(e._helper?e.offset.left-h.left:e.offset.left-s.left)),s=Math.abs(e.sizeDiff.height+(e._helper?e.offset.top-h.top:e.offset.top-s.top)),n+e.size.width>=e.parentData.width&&(e.size.width=e.parentData.width-n,o&&(e.size.height=e.size.width/e.aspectRatio,t=!1)),s+e.size.height>=e.parentData.height&&(e.size.height=e.parentData.height-s,o&&(e.size.width=e.size.height*e.aspectRatio,t=!1)),t||(e.position.left=e.prevPosition.left,e.position.top=e.prevPosition.top,e.size.width=e.prevSize.width,e.size.height=e.prevSize.height)},stop:function(){var t=y(this).resizable("instance"),e=t.options,i=t.containerOffset,s=t.containerPosition,n=t.containerElement,o=y(t.helper),h=o.offset(),a=o.outerWidth()-t.sizeDiff.width,o=o.outerHeight()-t.sizeDiff.height;t._helper&&!e.animate&&/relative/.test(n.css("position"))&&y(this).css({left:h.left-s.left-i.left,width:a,height:o}),t._helper&&!e.animate&&/static/.test(n.css("position"))&&y(this).css({left:h.left-s.left-i.left,width:a,height:o})}}),y.ui.plugin.add("resizable","alsoResize",{start:function(){var t=y(this).resizable("instance").options;y(t.alsoResize).each(function(){var t=y(this);t.data("ui-resizable-alsoresize",{width:parseFloat(t.width()),height:parseFloat(t.height()),left:parseFloat(t.css("left")),top:parseFloat(t.css("top"))})})},resize:function(t,i){var e=y(this).resizable("instance"),s=e.options,n=e.originalSize,o=e.originalPosition,h={height:e.size.height-n.height||0,width:e.size.width-n.width||0,top:e.position.top-o.top||0,left:e.position.left-o.left||0};y(s.alsoResize).each(function(){var t=y(this),s=y(this).data("ui-resizable-alsoresize"),n={},e=t.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];y.each(e,function(t,e){var i=(s[e]||0)+(h[e]||0);i&&0<=i&&(n[e]=i||null)}),t.css(n)})},stop:function(){y(this).removeData("ui-resizable-alsoresize")}}),y.ui.plugin.add("resizable","ghost",{start:function(){var t=y(this).resizable("instance"),e=t.size;t.ghost=t.originalElement.clone(),t.ghost.css({opacity:.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}),t._addClass(t.ghost,"ui-resizable-ghost"),!1!==y.uiBackCompat&&"string"==typeof t.options.ghost&&t.ghost.addClass(this.options.ghost),t.ghost.appendTo(t.helper)},resize:function(){var t=y(this).resizable("instance");t.ghost&&t.ghost.css({position:"relative",height:t.size.height,width:t.size.width})},stop:function(){var t=y(this).resizable("instance");t.ghost&&t.helper&&t.helper.get(0).removeChild(t.ghost.get(0))}}),y.ui.plugin.add("resizable","grid",{resize:function(){var t,e=y(this).resizable("instance"),i=e.options,s=e.size,n=e.originalSize,o=e.originalPosition,h=e.axis,a="number"==typeof i.grid?[i.grid,i.grid]:i.grid,r=a[0]||1,l=a[1]||1,u=Math.round((s.width-n.width)/r)*r,p=Math.round((s.height-n.height)/l)*l,d=n.width+u,c=n.height+p,f=i.maxWidth&&i.maxWidthd,s=i.minHeight&&i.minHeight>c;i.grid=a,m&&(d+=r),s&&(c+=l),f&&(d-=r),g&&(c-=l),/^(se|s|e)$/.test(h)?(e.size.width=d,e.size.height=c):/^(ne)$/.test(h)?(e.size.width=d,e.size.height=c,e.position.top=o.top-p):/^(sw)$/.test(h)?(e.size.width=d,e.size.height=c,e.position.left=o.left-u):((c-l<=0||d-r<=0)&&(t=e._getPaddingPlusBorderDimensions(this)),0=f[g]?0:Math.min(f[g],n));!a&&1-1){targetElements.on(evt+EVENT_NAMESPACE,function elementToggle(event){$.powerTip.toggle(this,event)})}else{targetElements.on(evt+EVENT_NAMESPACE,function elementOpen(event){$.powerTip.show(this,event)})}});$.each(options.closeEvents,function(idx,evt){if($.inArray(evt,options.openEvents)<0){targetElements.on(evt+EVENT_NAMESPACE,function elementClose(event){$.powerTip.hide(this,!isMouseEvent(event))})}});targetElements.on("keydown"+EVENT_NAMESPACE,function elementKeyDown(event){if(event.keyCode===27){$.powerTip.hide(this,true)}})}return targetElements};$.fn.powerTip.defaults={fadeInTime:200,fadeOutTime:100,followMouse:false,popupId:"powerTip",popupClass:null,intentSensitivity:7,intentPollInterval:100,closeDelay:100,placement:"n",smartPlacement:false,offset:10,mouseOnToPopup:false,manual:false,openEvents:["mouseenter","focus"],closeEvents:["mouseleave","blur"]};$.fn.powerTip.smartPlacementLists={n:["n","ne","nw","s"],e:["e","ne","se","w","nw","sw","n","s","e"],s:["s","se","sw","n"],w:["w","nw","sw","e","ne","se","n","s","w"],nw:["nw","w","sw","n","s","se","nw"],ne:["ne","e","se","n","s","sw","ne"],sw:["sw","w","nw","s","n","ne","sw"],se:["se","e","ne","s","n","nw","se"],"nw-alt":["nw-alt","n","ne-alt","sw-alt","s","se-alt","w","e"],"ne-alt":["ne-alt","n","nw-alt","se-alt","s","sw-alt","e","w"],"sw-alt":["sw-alt","s","se-alt","nw-alt","n","ne-alt","w","e"],"se-alt":["se-alt","s","sw-alt","ne-alt","n","nw-alt","e","w"]};$.powerTip={show:function apiShowTip(element,event){if(isMouseEvent(event)){trackMouse(event);session.previousX=event.pageX;session.previousY=event.pageY;$(element).data(DATA_DISPLAYCONTROLLER).show()}else{$(element).first().data(DATA_DISPLAYCONTROLLER).show(true,true)}return element},reposition:function apiResetPosition(element){$(element).first().data(DATA_DISPLAYCONTROLLER).resetPosition();return element},hide:function apiCloseTip(element,immediate){var displayController;immediate=element?immediate:true;if(element){displayController=$(element).first().data(DATA_DISPLAYCONTROLLER)}else if(session.activeHover){displayController=session.activeHover.data(DATA_DISPLAYCONTROLLER)}if(displayController){displayController.hide(immediate)}return element},toggle:function apiToggle(element,event){if(session.activeHover&&session.activeHover.is(element)){$.powerTip.hide(element,!isMouseEvent(event))}else{$.powerTip.show(element,event)}return element}};$.powerTip.showTip=$.powerTip.show;$.powerTip.closeTip=$.powerTip.hide;function CSSCoordinates(){var me=this;me.top="auto";me.left="auto";me.right="auto";me.bottom="auto";me.set=function(property,value){if($.isNumeric(value)){me[property]=Math.round(value)}}}function DisplayController(element,options,tipController){var hoverTimer=null,myCloseDelay=null;function openTooltip(immediate,forceOpen){cancelTimer();if(!element.data(DATA_HASACTIVEHOVER)){if(!immediate){session.tipOpenImminent=true;hoverTimer=setTimeout(function intentDelay(){hoverTimer=null;checkForIntent()},options.intentPollInterval)}else{if(forceOpen){element.data(DATA_FORCEDOPEN,true)}closeAnyDelayed();tipController.showTip(element)}}else{cancelClose()}}function closeTooltip(disableDelay){if(myCloseDelay){myCloseDelay=session.closeDelayTimeout=clearTimeout(myCloseDelay);session.delayInProgress=false}cancelTimer();session.tipOpenImminent=false;if(element.data(DATA_HASACTIVEHOVER)){element.data(DATA_FORCEDOPEN,false);if(!disableDelay){session.delayInProgress=true;session.closeDelayTimeout=setTimeout(function closeDelay(){session.closeDelayTimeout=null;tipController.hideTip(element);session.delayInProgress=false;myCloseDelay=null},options.closeDelay);myCloseDelay=session.closeDelayTimeout}else{tipController.hideTip(element)}}}function checkForIntent(){var xDifference=Math.abs(session.previousX-session.currentX),yDifference=Math.abs(session.previousY-session.currentY),totalDifference=xDifference+yDifference;if(totalDifference",{id:options.popupId});if($body.length===0){$body=$("body")}$body.append(tipElement);session.tooltips=session.tooltips?session.tooltips.add(tipElement):tipElement}if(options.followMouse){if(!tipElement.data(DATA_HASMOUSEMOVE)){$document.on("mousemove"+EVENT_NAMESPACE,positionTipOnCursor);$window.on("scroll"+EVENT_NAMESPACE,positionTipOnCursor);tipElement.data(DATA_HASMOUSEMOVE,true)}}function beginShowTip(element){element.data(DATA_HASACTIVEHOVER,true);tipElement.queue(function queueTipInit(next){showTip(element);next()})}function showTip(element){var tipContent;if(!element.data(DATA_HASACTIVEHOVER)){return}if(session.isTipOpen){if(!session.isClosing){hideTip(session.activeHover)}tipElement.delay(100).queue(function queueTipAgain(next){showTip(element);next()});return}element.trigger("powerTipPreRender");tipContent=getTooltipContent(element);if(tipContent){tipElement.empty().append(tipContent)}else{return}element.trigger("powerTipRender");session.activeHover=element;session.isTipOpen=true;tipElement.data(DATA_MOUSEONTOTIP,options.mouseOnToPopup);tipElement.addClass(options.popupClass);if(!options.followMouse||element.data(DATA_FORCEDOPEN)){positionTipOnElement(element);session.isFixedTipOpen=true}else{positionTipOnCursor()}if(!element.data(DATA_FORCEDOPEN)&&!options.followMouse){$document.on("click"+EVENT_NAMESPACE,function documentClick(event){var target=event.target;if(target!==element[0]){if(options.mouseOnToPopup){if(target!==tipElement[0]&&!$.contains(tipElement[0],target)){$.powerTip.hide()}}else{$.powerTip.hide()}}})}if(options.mouseOnToPopup&&!options.manual){tipElement.on("mouseenter"+EVENT_NAMESPACE,function tipMouseEnter(){if(session.activeHover){session.activeHover.data(DATA_DISPLAYCONTROLLER).cancel()}});tipElement.on("mouseleave"+EVENT_NAMESPACE,function tipMouseLeave(){if(session.activeHover){session.activeHover.data(DATA_DISPLAYCONTROLLER).hide()}})}tipElement.fadeIn(options.fadeInTime,function fadeInCallback(){if(!session.desyncTimeout){session.desyncTimeout=setInterval(closeDesyncedTip,500)}element.trigger("powerTipOpen")})}function hideTip(element){session.isClosing=true;session.isTipOpen=false;session.desyncTimeout=clearInterval(session.desyncTimeout);element.data(DATA_HASACTIVEHOVER,false);element.data(DATA_FORCEDOPEN,false);$document.off("click"+EVENT_NAMESPACE);tipElement.off(EVENT_NAMESPACE);tipElement.fadeOut(options.fadeOutTime,function fadeOutCallback(){var coords=new CSSCoordinates;session.activeHover=null;session.isClosing=false;session.isFixedTipOpen=false;tipElement.removeClass();coords.set("top",session.currentY+options.offset);coords.set("left",session.currentX+options.offset);tipElement.css(coords);element.trigger("powerTipClose")})}function positionTipOnCursor(){var tipWidth,tipHeight,coords,collisions,collisionCount;if(!session.isFixedTipOpen&&(session.isTipOpen||session.tipOpenImminent&&tipElement.data(DATA_HASMOUSEMOVE))){tipWidth=tipElement.outerWidth();tipHeight=tipElement.outerHeight();coords=new CSSCoordinates;coords.set("top",session.currentY+options.offset);coords.set("left",session.currentX+options.offset);collisions=getViewportCollisions(coords,tipWidth,tipHeight);if(collisions!==Collision.none){collisionCount=countFlags(collisions);if(collisionCount===1){if(collisions===Collision.right){coords.set("left",session.scrollLeft+session.windowWidth-tipWidth)}else if(collisions===Collision.bottom){coords.set("top",session.scrollTop+session.windowHeight-tipHeight)}}else{coords.set("left",session.currentX-tipWidth-options.offset);coords.set("top",session.currentY-tipHeight-options.offset)}}tipElement.css(coords)}}function positionTipOnElement(element){var priorityList,finalPlacement;if(options.smartPlacement||options.followMouse&&element.data(DATA_FORCEDOPEN)){priorityList=$.fn.powerTip.smartPlacementLists[options.placement];$.each(priorityList,function(idx,pos){var collisions=getViewportCollisions(placeTooltip(element,pos),tipElement.outerWidth(),tipElement.outerHeight());finalPlacement=pos;return collisions!==Collision.none})}else{placeTooltip(element,options.placement);finalPlacement=options.placement}tipElement.removeClass("w nw sw e ne se n s w se-alt sw-alt ne-alt nw-alt");tipElement.addClass(finalPlacement)}function placeTooltip(element,placement){var iterationCount=0,tipWidth,tipHeight,coords=new CSSCoordinates;coords.set("top",0);coords.set("left",0);tipElement.css(coords);do{tipWidth=tipElement.outerWidth();tipHeight=tipElement.outerHeight();coords=placementCalculator.compute(element,placement,tipWidth,tipHeight,options.offset);tipElement.css(coords)}while(++iterationCount<=5&&(tipWidth!==tipElement.outerWidth()||tipHeight!==tipElement.outerHeight()));return coords}function closeDesyncedTip(){var isDesynced=false,hasDesyncableCloseEvent=$.grep(["mouseleave","mouseout","blur","focusout"],function(eventType){return $.inArray(eventType,options.closeEvents)!==-1}).length>0;if(session.isTipOpen&&!session.isClosing&&!session.delayInProgress&&hasDesyncableCloseEvent){if(session.activeHover.data(DATA_HASACTIVEHOVER)===false||session.activeHover.is(":disabled")){isDesynced=true}else if(!isMouseOver(session.activeHover)&&!session.activeHover.is(":focus")&&!session.activeHover.data(DATA_FORCEDOPEN)){if(tipElement.data(DATA_MOUSEONTOTIP)){if(!isMouseOver(tipElement)){isDesynced=true}}else{isDesynced=true}}if(isDesynced){hideTip(session.activeHover)}}}this.showTip=beginShowTip;this.hideTip=hideTip;this.resetPosition=positionTipOnElement}function isSvgElement(element){return Boolean(window.SVGElement&&element[0]instanceof SVGElement)}function isMouseEvent(event){return Boolean(event&&$.inArray(event.type,MOUSE_EVENTS)>-1&&typeof event.pageX==="number")}function initTracking(){if(!session.mouseTrackingActive){session.mouseTrackingActive=true;getViewportDimensions();$(getViewportDimensions);$document.on("mousemove"+EVENT_NAMESPACE,trackMouse);$window.on("resize"+EVENT_NAMESPACE,trackResize);$window.on("scroll"+EVENT_NAMESPACE,trackScroll)}}function getViewportDimensions(){session.scrollLeft=$window.scrollLeft();session.scrollTop=$window.scrollTop();session.windowWidth=$window.width();session.windowHeight=$window.height()}function trackResize(){session.windowWidth=$window.width();session.windowHeight=$window.height()}function trackScroll(){var x=$window.scrollLeft(),y=$window.scrollTop();if(x!==session.scrollLeft){session.currentX+=x-session.scrollLeft;session.scrollLeft=x}if(y!==session.scrollTop){session.currentY+=y-session.scrollTop;session.scrollTop=y}}function trackMouse(event){session.currentX=event.pageX;session.currentY=event.pageY}function isMouseOver(element){var elementPosition=element.offset(),elementBox=element[0].getBoundingClientRect(),elementWidth=elementBox.right-elementBox.left,elementHeight=elementBox.bottom-elementBox.top;return session.currentX>=elementPosition.left&&session.currentX<=elementPosition.left+elementWidth&&session.currentY>=elementPosition.top&&session.currentY<=elementPosition.top+elementHeight}function getTooltipContent(element){var tipText=element.data(DATA_POWERTIP),tipObject=element.data(DATA_POWERTIPJQ),tipTarget=element.data(DATA_POWERTIPTARGET),targetElement,content;if(tipText){if($.isFunction(tipText)){tipText=tipText.call(element[0])}content=tipText}else if(tipObject){if($.isFunction(tipObject)){tipObject=tipObject.call(element[0])}if(tipObject.length>0){content=tipObject.clone(true,true)}}else if(tipTarget){targetElement=$("#"+tipTarget);if(targetElement.length>0){content=targetElement.html()}}return content}function getViewportCollisions(coords,elementWidth,elementHeight){var viewportTop=session.scrollTop,viewportLeft=session.scrollLeft,viewportBottom=viewportTop+session.windowHeight,viewportRight=viewportLeft+session.windowWidth,collisions=Collision.none;if(coords.topviewportBottom||Math.abs(coords.bottom-session.windowHeight)>viewportBottom){collisions|=Collision.bottom}if(coords.leftviewportRight){collisions|=Collision.left}if(coords.left+elementWidth>viewportRight||coords.right1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery);/*! SmartMenus jQuery Plugin - v1.1.0 - September 17, 2017 + * http://www.smartmenus.org/ + * Copyright Vasil Dinkov, Vadikom Web Ltd. http://vadikom.com; Licensed MIT */(function(t){"function"==typeof define&&define.amd?define(["jquery"],t):"object"==typeof module&&"object"==typeof module.exports?module.exports=t(require("jquery")):t(jQuery)})(function($){function initMouseDetection(t){var e=".smartmenus_mouse";if(mouseDetectionEnabled||t)mouseDetectionEnabled&&t&&($(document).off(e),mouseDetectionEnabled=!1);else{var i=!0,s=null,o={mousemove:function(t){var e={x:t.pageX,y:t.pageY,timeStamp:(new Date).getTime()};if(s){var o=Math.abs(s.x-e.x),a=Math.abs(s.y-e.y);if((o>0||a>0)&&2>=o&&2>=a&&300>=e.timeStamp-s.timeStamp&&(mouse=!0,i)){var n=$(t.target).closest("a");n.is("a")&&$.each(menuTrees,function(){return $.contains(this.$root[0],n[0])?(this.itemEnter({currentTarget:n[0]}),!1):void 0}),i=!1}}s=e}};o[touchEvents?"touchstart":"pointerover pointermove pointerout MSPointerOver MSPointerMove MSPointerOut"]=function(t){isTouchEvent(t.originalEvent)&&(mouse=!1)},$(document).on(getEventsNS(o,e)),mouseDetectionEnabled=!0}}function isTouchEvent(t){return!/^(4|mouse)$/.test(t.pointerType)}function getEventsNS(t,e){e||(e="");var i={};for(var s in t)i[s.split(" ").join(e+" ")+e]=t[s];return i}var menuTrees=[],mouse=!1,touchEvents="ontouchstart"in window,mouseDetectionEnabled=!1,requestAnimationFrame=window.requestAnimationFrame||function(t){return setTimeout(t,1e3/60)},cancelAnimationFrame=window.cancelAnimationFrame||function(t){clearTimeout(t)},canAnimate=!!$.fn.animate;return $.SmartMenus=function(t,e){this.$root=$(t),this.opts=e,this.rootId="",this.accessIdPrefix="",this.$subArrow=null,this.activatedItems=[],this.visibleSubMenus=[],this.showTimeout=0,this.hideTimeout=0,this.scrollTimeout=0,this.clickActivated=!1,this.focusActivated=!1,this.zIndexInc=0,this.idInc=0,this.$firstLink=null,this.$firstSub=null,this.disabled=!1,this.$disableOverlay=null,this.$touchScrollingSub=null,this.cssTransforms3d="perspective"in t.style||"webkitPerspective"in t.style,this.wasCollapsible=!1,this.init()},$.extend($.SmartMenus,{hideAll:function(){$.each(menuTrees,function(){this.menuHideAll()})},destroy:function(){for(;menuTrees.length;)menuTrees[0].destroy();initMouseDetection(!0)},prototype:{init:function(t){var e=this;if(!t){menuTrees.push(this),this.rootId=((new Date).getTime()+Math.random()+"").replace(/\D/g,""),this.accessIdPrefix="sm-"+this.rootId+"-",this.$root.hasClass("sm-rtl")&&(this.opts.rightToLeftSubMenus=!0);var i=".smartmenus";this.$root.data("smartmenus",this).attr("data-smartmenus-id",this.rootId).dataSM("level",1).on(getEventsNS({"mouseover focusin":$.proxy(this.rootOver,this),"mouseout focusout":$.proxy(this.rootOut,this),keydown:$.proxy(this.rootKeyDown,this)},i)).on(getEventsNS({mouseenter:$.proxy(this.itemEnter,this),mouseleave:$.proxy(this.itemLeave,this),mousedown:$.proxy(this.itemDown,this),focus:$.proxy(this.itemFocus,this),blur:$.proxy(this.itemBlur,this),click:$.proxy(this.itemClick,this)},i),"a"),i+=this.rootId,this.opts.hideOnClick&&$(document).on(getEventsNS({touchstart:$.proxy(this.docTouchStart,this),touchmove:$.proxy(this.docTouchMove,this),touchend:$.proxy(this.docTouchEnd,this),click:$.proxy(this.docClick,this)},i)),$(window).on(getEventsNS({"resize orientationchange":$.proxy(this.winResize,this)},i)),this.opts.subIndicators&&(this.$subArrow=$("").addClass("sub-arrow"),this.opts.subIndicatorsText&&this.$subArrow.html(this.opts.subIndicatorsText)),initMouseDetection()}if(this.$firstSub=this.$root.find("ul").each(function(){e.menuInit($(this))}).eq(0),this.$firstLink=this.$root.find("a").eq(0),this.opts.markCurrentItem){var s=/(index|default)\.[^#\?\/]*/i,o=/#.*/,a=window.location.href.replace(s,""),n=a.replace(o,"");this.$root.find("a").each(function(){var t=this.href.replace(s,""),i=$(this);(t==a||t==n)&&(i.addClass("current"),e.opts.markCurrentTree&&i.parentsUntil("[data-smartmenus-id]","ul").each(function(){$(this).dataSM("parent-a").addClass("current")}))})}this.wasCollapsible=this.isCollapsible()},destroy:function(t){if(!t){var e=".smartmenus";this.$root.removeData("smartmenus").removeAttr("data-smartmenus-id").removeDataSM("level").off(e),e+=this.rootId,$(document).off(e),$(window).off(e),this.opts.subIndicators&&(this.$subArrow=null)}this.menuHideAll();var i=this;this.$root.find("ul").each(function(){var t=$(this);t.dataSM("scroll-arrows")&&t.dataSM("scroll-arrows").remove(),t.dataSM("shown-before")&&((i.opts.subMenusMinWidth||i.opts.subMenusMaxWidth)&&t.css({width:"",minWidth:"",maxWidth:""}).removeClass("sm-nowrap"),t.dataSM("scroll-arrows")&&t.dataSM("scroll-arrows").remove(),t.css({zIndex:"",top:"",left:"",marginLeft:"",marginTop:"",display:""})),0==(t.attr("id")||"").indexOf(i.accessIdPrefix)&&t.removeAttr("id")}).removeDataSM("in-mega").removeDataSM("shown-before").removeDataSM("scroll-arrows").removeDataSM("parent-a").removeDataSM("level").removeDataSM("beforefirstshowfired").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeAttr("aria-expanded"),this.$root.find("a.has-submenu").each(function(){var t=$(this);0==t.attr("id").indexOf(i.accessIdPrefix)&&t.removeAttr("id")}).removeClass("has-submenu").removeDataSM("sub").removeAttr("aria-haspopup").removeAttr("aria-controls").removeAttr("aria-expanded").closest("li").removeDataSM("sub"),this.opts.subIndicators&&this.$root.find("span.sub-arrow").remove(),this.opts.markCurrentItem&&this.$root.find("a.current").removeClass("current"),t||(this.$root=null,this.$firstLink=null,this.$firstSub=null,this.$disableOverlay&&(this.$disableOverlay.remove(),this.$disableOverlay=null),menuTrees.splice($.inArray(this,menuTrees),1))},disable:function(t){if(!this.disabled){if(this.menuHideAll(),!t&&!this.opts.isPopup&&this.$root.is(":visible")){var e=this.$root.offset();this.$disableOverlay=$('
').css({position:"absolute",top:e.top,left:e.left,width:this.$root.outerWidth(),height:this.$root.outerHeight(),zIndex:this.getStartZIndex(!0),opacity:0}).appendTo(document.body)}this.disabled=!0}},docClick:function(t){return this.$touchScrollingSub?(this.$touchScrollingSub=null,void 0):((this.visibleSubMenus.length&&!$.contains(this.$root[0],t.target)||$(t.target).closest("a").length)&&this.menuHideAll(),void 0)},docTouchEnd:function(){if(this.lastTouch){if(!(!this.visibleSubMenus.length||void 0!==this.lastTouch.x2&&this.lastTouch.x1!=this.lastTouch.x2||void 0!==this.lastTouch.y2&&this.lastTouch.y1!=this.lastTouch.y2||this.lastTouch.target&&$.contains(this.$root[0],this.lastTouch.target))){this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0);var t=this;this.hideTimeout=setTimeout(function(){t.menuHideAll()},350)}this.lastTouch=null}},docTouchMove:function(t){if(this.lastTouch){var e=t.originalEvent.touches[0];this.lastTouch.x2=e.pageX,this.lastTouch.y2=e.pageY}},docTouchStart:function(t){var e=t.originalEvent.touches[0];this.lastTouch={x1:e.pageX,y1:e.pageY,target:e.target}},enable:function(){this.disabled&&(this.$disableOverlay&&(this.$disableOverlay.remove(),this.$disableOverlay=null),this.disabled=!1)},getClosestMenu:function(t){for(var e=$(t).closest("ul");e.dataSM("in-mega");)e=e.parent().closest("ul");return e[0]||null},getHeight:function(t){return this.getOffset(t,!0)},getOffset:function(t,e){var i;"none"==t.css("display")&&(i={position:t[0].style.position,visibility:t[0].style.visibility},t.css({position:"absolute",visibility:"hidden"}).show());var s=t[0].getBoundingClientRect&&t[0].getBoundingClientRect(),o=s&&(e?s.height||s.bottom-s.top:s.width||s.right-s.left);return o||0===o||(o=e?t[0].offsetHeight:t[0].offsetWidth),i&&t.hide().css(i),o},getStartZIndex:function(t){var e=parseInt(this[t?"$root":"$firstSub"].css("z-index"));return!t&&isNaN(e)&&(e=parseInt(this.$root.css("z-index"))),isNaN(e)?1:e},getTouchPoint:function(t){return t.touches&&t.touches[0]||t.changedTouches&&t.changedTouches[0]||t},getViewport:function(t){var e=t?"Height":"Width",i=document.documentElement["client"+e],s=window["inner"+e];return s&&(i=Math.min(i,s)),i},getViewportHeight:function(){return this.getViewport(!0)},getViewportWidth:function(){return this.getViewport()},getWidth:function(t){return this.getOffset(t)},handleEvents:function(){return!this.disabled&&this.isCSSOn()},handleItemEvents:function(t){return this.handleEvents()&&!this.isLinkInMegaMenu(t)},isCollapsible:function(){return"static"==this.$firstSub.css("position")},isCSSOn:function(){return"inline"!=this.$firstLink.css("display")},isFixed:function(){var t="fixed"==this.$root.css("position");return t||this.$root.parentsUntil("body").each(function(){return"fixed"==$(this).css("position")?(t=!0,!1):void 0}),t},isLinkInMegaMenu:function(t){return $(this.getClosestMenu(t[0])).hasClass("mega-menu")},isTouchMode:function(){return!mouse||this.opts.noMouseOver||this.isCollapsible()},itemActivate:function(t,e){var i=t.closest("ul"),s=i.dataSM("level");if(s>1&&(!this.activatedItems[s-2]||this.activatedItems[s-2][0]!=i.dataSM("parent-a")[0])){var o=this;$(i.parentsUntil("[data-smartmenus-id]","ul").get().reverse()).add(i).each(function(){o.itemActivate($(this).dataSM("parent-a"))})}if((!this.isCollapsible()||e)&&this.menuHideSubMenus(this.activatedItems[s-1]&&this.activatedItems[s-1][0]==t[0]?s:s-1),this.activatedItems[s-1]=t,this.$root.triggerHandler("activate.smapi",t[0])!==!1){var a=t.dataSM("sub");a&&(this.isTouchMode()||!this.opts.showOnClick||this.clickActivated)&&this.menuShow(a)}},itemBlur:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&this.$root.triggerHandler("blur.smapi",e[0])},itemClick:function(t){var e=$(t.currentTarget);if(this.handleItemEvents(e)){if(this.$touchScrollingSub&&this.$touchScrollingSub[0]==e.closest("ul")[0])return this.$touchScrollingSub=null,t.stopPropagation(),!1;if(this.$root.triggerHandler("click.smapi",e[0])===!1)return!1;var i=$(t.target).is(".sub-arrow"),s=e.dataSM("sub"),o=s?2==s.dataSM("level"):!1,a=this.isCollapsible(),n=/toggle$/.test(this.opts.collapsibleBehavior),r=/link$/.test(this.opts.collapsibleBehavior),h=/^accordion/.test(this.opts.collapsibleBehavior);if(s&&!s.is(":visible")){if((!r||!a||i)&&(this.opts.showOnClick&&o&&(this.clickActivated=!0),this.itemActivate(e,h),s.is(":visible")))return this.focusActivated=!0,!1}else if(a&&(n||i))return this.itemActivate(e,h),this.menuHide(s),n&&(this.focusActivated=!1),!1;return this.opts.showOnClick&&o||e.hasClass("disabled")||this.$root.triggerHandler("select.smapi",e[0])===!1?!1:void 0}},itemDown:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&e.dataSM("mousedown",!0)},itemEnter:function(t){var e=$(t.currentTarget);if(this.handleItemEvents(e)){if(!this.isTouchMode()){this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0);var i=this;this.showTimeout=setTimeout(function(){i.itemActivate(e)},this.opts.showOnClick&&1==e.closest("ul").dataSM("level")?1:this.opts.showTimeout)}this.$root.triggerHandler("mouseenter.smapi",e[0])}},itemFocus:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&(!this.focusActivated||this.isTouchMode()&&e.dataSM("mousedown")||this.activatedItems.length&&this.activatedItems[this.activatedItems.length-1][0]==e[0]||this.itemActivate(e,!0),this.$root.triggerHandler("focus.smapi",e[0]))},itemLeave:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&(this.isTouchMode()||(e[0].blur(),this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0)),e.removeDataSM("mousedown"),this.$root.triggerHandler("mouseleave.smapi",e[0]))},menuHide:function(t){if(this.$root.triggerHandler("beforehide.smapi",t[0])!==!1&&(canAnimate&&t.stop(!0,!0),"none"!=t.css("display"))){var e=function(){t.css("z-index","")};this.isCollapsible()?canAnimate&&this.opts.collapsibleHideFunction?this.opts.collapsibleHideFunction.call(this,t,e):t.hide(this.opts.collapsibleHideDuration,e):canAnimate&&this.opts.hideFunction?this.opts.hideFunction.call(this,t,e):t.hide(this.opts.hideDuration,e),t.dataSM("scroll")&&(this.menuScrollStop(t),t.css({"touch-action":"","-ms-touch-action":"","-webkit-transform":"",transform:""}).off(".smartmenus_scroll").removeDataSM("scroll").dataSM("scroll-arrows").hide()),t.dataSM("parent-a").removeClass("highlighted").attr("aria-expanded","false"),t.attr({"aria-expanded":"false","aria-hidden":"true"});var i=t.dataSM("level");this.activatedItems.splice(i-1,1),this.visibleSubMenus.splice($.inArray(t,this.visibleSubMenus),1),this.$root.triggerHandler("hide.smapi",t[0])}},menuHideAll:function(){this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0);for(var t=this.opts.isPopup?1:0,e=this.visibleSubMenus.length-1;e>=t;e--)this.menuHide(this.visibleSubMenus[e]);this.opts.isPopup&&(canAnimate&&this.$root.stop(!0,!0),this.$root.is(":visible")&&(canAnimate&&this.opts.hideFunction?this.opts.hideFunction.call(this,this.$root):this.$root.hide(this.opts.hideDuration))),this.activatedItems=[],this.visibleSubMenus=[],this.clickActivated=!1,this.focusActivated=!1,this.zIndexInc=0,this.$root.triggerHandler("hideAll.smapi")},menuHideSubMenus:function(t){for(var e=this.activatedItems.length-1;e>=t;e--){var i=this.activatedItems[e].dataSM("sub");i&&this.menuHide(i)}},menuInit:function(t){if(!t.dataSM("in-mega")){t.hasClass("mega-menu")&&t.find("ul").dataSM("in-mega",!0);for(var e=2,i=t[0];(i=i.parentNode.parentNode)!=this.$root[0];)e++;var s=t.prevAll("a").eq(-1);s.length||(s=t.prevAll().find("a").eq(-1)),s.addClass("has-submenu").dataSM("sub",t),t.dataSM("parent-a",s).dataSM("level",e).parent().dataSM("sub",t);var o=s.attr("id")||this.accessIdPrefix+ ++this.idInc,a=t.attr("id")||this.accessIdPrefix+ ++this.idInc;s.attr({id:o,"aria-haspopup":"true","aria-controls":a,"aria-expanded":"false"}),t.attr({id:a,role:"group","aria-hidden":"true","aria-labelledby":o,"aria-expanded":"false"}),this.opts.subIndicators&&s[this.opts.subIndicatorsPos](this.$subArrow.clone())}},menuPosition:function(t){var e,i,s=t.dataSM("parent-a"),o=s.closest("li"),a=o.parent(),n=t.dataSM("level"),r=this.getWidth(t),h=this.getHeight(t),u=s.offset(),l=u.left,c=u.top,d=this.getWidth(s),m=this.getHeight(s),p=$(window),f=p.scrollLeft(),v=p.scrollTop(),b=this.getViewportWidth(),S=this.getViewportHeight(),g=a.parent().is("[data-sm-horizontal-sub]")||2==n&&!a.hasClass("sm-vertical"),M=this.opts.rightToLeftSubMenus&&!o.is("[data-sm-reverse]")||!this.opts.rightToLeftSubMenus&&o.is("[data-sm-reverse]"),w=2==n?this.opts.mainMenuSubOffsetX:this.opts.subMenusSubOffsetX,T=2==n?this.opts.mainMenuSubOffsetY:this.opts.subMenusSubOffsetY;if(g?(e=M?d-r-w:w,i=this.opts.bottomToTopSubMenus?-h-T:m+T):(e=M?w-r:d-w,i=this.opts.bottomToTopSubMenus?m-T-h:T),this.opts.keepInViewport){var y=l+e,I=c+i;if(M&&f>y?e=g?f-y+e:d-w:!M&&y+r>f+b&&(e=g?f+b-r-y+e:w-r),g||(S>h&&I+h>v+S?i+=v+S-h-I:(h>=S||v>I)&&(i+=v-I)),g&&(I+h>v+S+.49||v>I)||!g&&h>S+.49){var x=this;t.dataSM("scroll-arrows")||t.dataSM("scroll-arrows",$([$('')[0],$('')[0]]).on({mouseenter:function(){t.dataSM("scroll").up=$(this).hasClass("scroll-up"),x.menuScroll(t)},mouseleave:function(e){x.menuScrollStop(t),x.menuScrollOut(t,e)},"mousewheel DOMMouseScroll":function(t){t.preventDefault()}}).insertAfter(t));var A=".smartmenus_scroll";if(t.dataSM("scroll",{y:this.cssTransforms3d?0:i-m,step:1,itemH:m,subH:h,arrowDownH:this.getHeight(t.dataSM("scroll-arrows").eq(1))}).on(getEventsNS({mouseover:function(e){x.menuScrollOver(t,e)},mouseout:function(e){x.menuScrollOut(t,e)},"mousewheel DOMMouseScroll":function(e){x.menuScrollMousewheel(t,e)}},A)).dataSM("scroll-arrows").css({top:"auto",left:"0",marginLeft:e+(parseInt(t.css("border-left-width"))||0),width:r-(parseInt(t.css("border-left-width"))||0)-(parseInt(t.css("border-right-width"))||0),zIndex:t.css("z-index")}).eq(g&&this.opts.bottomToTopSubMenus?0:1).show(),this.isFixed()){var C={};C[touchEvents?"touchstart touchmove touchend":"pointerdown pointermove pointerup MSPointerDown MSPointerMove MSPointerUp"]=function(e){x.menuScrollTouch(t,e)},t.css({"touch-action":"none","-ms-touch-action":"none"}).on(getEventsNS(C,A))}}}t.css({top:"auto",left:"0",marginLeft:e,marginTop:i-m})},menuScroll:function(t,e,i){var s,o=t.dataSM("scroll"),a=t.dataSM("scroll-arrows"),n=o.up?o.upEnd:o.downEnd;if(!e&&o.momentum){if(o.momentum*=.92,s=o.momentum,.5>s)return this.menuScrollStop(t),void 0}else s=i||(e||!this.opts.scrollAccelerate?this.opts.scrollStep:Math.floor(o.step));var r=t.dataSM("level");if(this.activatedItems[r-1]&&this.activatedItems[r-1].dataSM("sub")&&this.activatedItems[r-1].dataSM("sub").is(":visible")&&this.menuHideSubMenus(r-1),o.y=o.up&&o.y>=n||!o.up&&n>=o.y?o.y:Math.abs(n-o.y)>s?o.y+(o.up?s:-s):n,t.css(this.cssTransforms3d?{"-webkit-transform":"translate3d(0, "+o.y+"px, 0)",transform:"translate3d(0, "+o.y+"px, 0)"}:{marginTop:o.y}),mouse&&(o.up&&o.y>o.downEnd||!o.up&&o.y0;t.dataSM("scroll-arrows").eq(i?0:1).is(":visible")&&(t.dataSM("scroll").up=i,this.menuScroll(t,!0))}e.preventDefault()},menuScrollOut:function(t,e){mouse&&(/^scroll-(up|down)/.test((e.relatedTarget||"").className)||(t[0]==e.relatedTarget||$.contains(t[0],e.relatedTarget))&&this.getClosestMenu(e.relatedTarget)==t[0]||t.dataSM("scroll-arrows").css("visibility","hidden"))},menuScrollOver:function(t,e){if(mouse&&!/^scroll-(up|down)/.test(e.target.className)&&this.getClosestMenu(e.target)==t[0]){this.menuScrollRefreshData(t);var i=t.dataSM("scroll"),s=$(window).scrollTop()-t.dataSM("parent-a").offset().top-i.itemH;t.dataSM("scroll-arrows").eq(0).css("margin-top",s).end().eq(1).css("margin-top",s+this.getViewportHeight()-i.arrowDownH).end().css("visibility","visible")}},menuScrollRefreshData:function(t){var e=t.dataSM("scroll"),i=$(window).scrollTop()-t.dataSM("parent-a").offset().top-e.itemH;this.cssTransforms3d&&(i=-(parseFloat(t.css("margin-top"))-i)),$.extend(e,{upEnd:i,downEnd:i+this.getViewportHeight()-e.subH})},menuScrollStop:function(t){return this.scrollTimeout?(cancelAnimationFrame(this.scrollTimeout),this.scrollTimeout=0,t.dataSM("scroll").step=1,!0):void 0},menuScrollTouch:function(t,e){if(e=e.originalEvent,isTouchEvent(e)){var i=this.getTouchPoint(e);if(this.getClosestMenu(i.target)==t[0]){var s=t.dataSM("scroll");if(/(start|down)$/i.test(e.type))this.menuScrollStop(t)?(e.preventDefault(),this.$touchScrollingSub=t):this.$touchScrollingSub=null,this.menuScrollRefreshData(t),$.extend(s,{touchStartY:i.pageY,touchStartTime:e.timeStamp});else if(/move$/i.test(e.type)){var o=void 0!==s.touchY?s.touchY:s.touchStartY;if(void 0!==o&&o!=i.pageY){this.$touchScrollingSub=t;var a=i.pageY>o;void 0!==s.up&&s.up!=a&&$.extend(s,{touchStartY:i.pageY,touchStartTime:e.timeStamp}),$.extend(s,{up:a,touchY:i.pageY}),this.menuScroll(t,!0,Math.abs(i.pageY-o))}e.preventDefault()}else void 0!==s.touchY&&((s.momentum=15*Math.pow(Math.abs(i.pageY-s.touchStartY)/(e.timeStamp-s.touchStartTime),2))&&(this.menuScrollStop(t),this.menuScroll(t),e.preventDefault()),delete s.touchY)}}},menuShow:function(t){if((t.dataSM("beforefirstshowfired")||(t.dataSM("beforefirstshowfired",!0),this.$root.triggerHandler("beforefirstshow.smapi",t[0])!==!1))&&this.$root.triggerHandler("beforeshow.smapi",t[0])!==!1&&(t.dataSM("shown-before",!0),canAnimate&&t.stop(!0,!0),!t.is(":visible"))){var e=t.dataSM("parent-a"),i=this.isCollapsible();if((this.opts.keepHighlighted||i)&&e.addClass("highlighted"),i)t.removeClass("sm-nowrap").css({zIndex:"",width:"auto",minWidth:"",maxWidth:"",top:"",left:"",marginLeft:"",marginTop:""});else{if(t.css("z-index",this.zIndexInc=(this.zIndexInc||this.getStartZIndex())+1),(this.opts.subMenusMinWidth||this.opts.subMenusMaxWidth)&&(t.css({width:"auto",minWidth:"",maxWidth:""}).addClass("sm-nowrap"),this.opts.subMenusMinWidth&&t.css("min-width",this.opts.subMenusMinWidth),this.opts.subMenusMaxWidth)){var s=this.getWidth(t);t.css("max-width",this.opts.subMenusMaxWidth),s>this.getWidth(t)&&t.removeClass("sm-nowrap").css("width",this.opts.subMenusMaxWidth)}this.menuPosition(t)}var o=function(){t.css("overflow","")};i?canAnimate&&this.opts.collapsibleShowFunction?this.opts.collapsibleShowFunction.call(this,t,o):t.show(this.opts.collapsibleShowDuration,o):canAnimate&&this.opts.showFunction?this.opts.showFunction.call(this,t,o):t.show(this.opts.showDuration,o),e.attr("aria-expanded","true"),t.attr({"aria-expanded":"true","aria-hidden":"false"}),this.visibleSubMenus.push(t),this.$root.triggerHandler("show.smapi",t[0])}},popupHide:function(t){this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0);var e=this;this.hideTimeout=setTimeout(function(){e.menuHideAll()},t?1:this.opts.hideTimeout)},popupShow:function(t,e){if(!this.opts.isPopup)return alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.'),void 0;if(this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0),this.$root.dataSM("shown-before",!0),canAnimate&&this.$root.stop(!0,!0),!this.$root.is(":visible")){this.$root.css({left:t,top:e});var i=this,s=function(){i.$root.css("overflow","")};canAnimate&&this.opts.showFunction?this.opts.showFunction.call(this,this.$root,s):this.$root.show(this.opts.showDuration,s),this.visibleSubMenus[0]=this.$root}},refresh:function(){this.destroy(!0),this.init(!0)},rootKeyDown:function(t){if(this.handleEvents())switch(t.keyCode){case 27:var e=this.activatedItems[0];if(e){this.menuHideAll(),e[0].focus();var i=e.dataSM("sub");i&&this.menuHide(i)}break;case 32:var s=$(t.target);if(s.is("a")&&this.handleItemEvents(s)){var i=s.dataSM("sub");i&&!i.is(":visible")&&(this.itemClick({currentTarget:t.target}),t.preventDefault())}}},rootOut:function(t){if(this.handleEvents()&&!this.isTouchMode()&&t.target!=this.$root[0]&&(this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0),!this.opts.showOnClick||!this.opts.hideOnClick)){var e=this;this.hideTimeout=setTimeout(function(){e.menuHideAll()},this.opts.hideTimeout)}},rootOver:function(t){this.handleEvents()&&!this.isTouchMode()&&t.target!=this.$root[0]&&this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0)},winResize:function(t){if(this.handleEvents()){if(!("onorientationchange"in window)||"orientationchange"==t.type){var e=this.isCollapsible();this.wasCollapsible&&e||(this.activatedItems.length&&this.activatedItems[this.activatedItems.length-1][0].blur(),this.menuHideAll()),this.wasCollapsible=e}}else if(this.$disableOverlay){var i=this.$root.offset();this.$disableOverlay.css({top:i.top,left:i.left,width:this.$root.outerWidth(),height:this.$root.outerHeight()})}}}}),$.fn.dataSM=function(t,e){return e?this.data(t+"_smartmenus",e):this.data(t+"_smartmenus")},$.fn.removeDataSM=function(t){return this.removeData(t+"_smartmenus")},$.fn.smartmenus=function(options){if("string"==typeof options){var args=arguments,method=options;return Array.prototype.shift.call(args),this.each(function(){var t=$(this).data("smartmenus");t&&t[method]&&t[method].apply(t,args)})}return this.each(function(){var dataOpts=$(this).data("sm-options")||null;if(dataOpts)try{dataOpts=eval("("+dataOpts+")")}catch(e){dataOpts=null,alert('ERROR\n\nSmartMenus jQuery init:\nInvalid "data-sm-options" attribute value syntax.')}new $.SmartMenus(this,$.extend({},$.fn.smartmenus.defaults,options,dataOpts))})},$.fn.smartmenus.defaults={isPopup:!1,mainMenuSubOffsetX:0,mainMenuSubOffsetY:0,subMenusSubOffsetX:0,subMenusSubOffsetY:0,subMenusMinWidth:"10em",subMenusMaxWidth:"20em",subIndicators:!0,subIndicatorsPos:"append",subIndicatorsText:"",scrollStep:30,scrollAccelerate:!0,showTimeout:250,hideTimeout:500,showDuration:0,showFunction:null,hideDuration:0,hideFunction:function(t,e){t.fadeOut(200,e)},collapsibleShowDuration:0,collapsibleShowFunction:function(t,e){t.slideDown(200,e)},collapsibleHideDuration:0,collapsibleHideFunction:function(t,e){t.slideUp(200,e)},showOnClick:!1,hideOnClick:!0,noMouseOver:!1,keepInViewport:!0,keepHighlighted:!0,markCurrentItem:!1,markCurrentTree:!0,rightToLeftSubMenus:!1,bottomToTopSubMenus:!1,collapsibleBehavior:"default"},$}); \ No newline at end of file diff --git a/apidoc/html/md_CHANGELOG.html b/apidoc/html/md_CHANGELOG.html new file mode 100644 index 0000000..8aa4594 --- /dev/null +++ b/apidoc/html/md_CHANGELOG.html @@ -0,0 +1,116 @@ + + + + + + + +smax-clib: Changelog + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
Changelog
+
+
+

All notable changes to the Smithsonian/redisx library will be documented in this file.

+

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

+

+[Unreleased]

+

Initial public release.

+
+
+
+ + + + diff --git a/apidoc/html/md_CONTRIBUTING.html b/apidoc/html/md_CONTRIBUTING.html new file mode 100644 index 0000000..729289a --- /dev/null +++ b/apidoc/html/md_CONTRIBUTING.html @@ -0,0 +1,124 @@ + + + + + + + +smax-clib: Contributing to RedisX + + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
smax-clib v0.9 +
+
A C/C++ client library for SMA-X
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
Contributing to RedisX
+
+
+

+

The SMA-X C/C++ library is for everyone. And, it is developers like you who can make it better. Whether there is a nagging issue you would like to fix, or a new feature you'd like to see, you can make a difference yourself. Make this project a little bit your own, by submitting pull requests with fixes and enhancement. When you are ready, here are the typical steps for contributing to the project:

+
    +
  1. Old or new Issue? Whether you just found a bug, or you are missing a much needed feature, start by checking open (and closed) Issues. If an existing issue seems like a good match to yours, feel free to speak up, comment, or to offer help in resolving it. If you find no issues that match, go ahead and create a new one.
  2. +
  3. Fork. Is it something you'd like to help resolve? Great! You should start by creating your own fork of the repository so you can work freely on your solution. I recommend that you place your work on a branch of your fork, which is named either after the issue number, e.g. issue-192, or some other descriptive name, such as sentinel-support.
  4. +
  5. Develop. Experiment on your fork/branch freely. If you run into a dead-end, you can always abandon it (which is why branches are great) and start anew. You can run make all to ensure that all components of the package and its API documentation are also in order. Remember to synchronize your main branch by fetching changes from upstream every once in a while, and merging them into your development branch. Don't forget to:
      +
    • Add doxygen markup your new code. You can keep it sweet and simple, but make sure it properly explains your globally exposed functions, their arguments and return values. You should also cross-reference other functions / constants that are similar, related, or relevant to what you just added.
    • +
    +
  6. +
  7. Pull Request. Once you feel your work can be integrated, create a pull request from your fork/branch. You can do that easily from the github page of your fork/branch directly. In the pull request, provide a concise description of what you added or changed. Your pull request will be reviewed. You may get some feedback at this point, and maybe there will be discussions about possible improvements or regressions etc. It's a good thing too, and your changes will likely end up with added polish as a result. You can be all the more proud of it in the end!
  8. +
  9. If all goes well, your pull-request will get merged, and will be included in the upcoming release of smax-clib. Congratulations for your excellent work, and many thanks for dedicating some of your time for making this library a little bit better. There will be many who will appreciate it. :-)
  10. +
+

If at any point you have questions, or need feedback, don't be afraid to ask. You can put your questions into the issue you found or created, or your pull-request, or as a Q&A in Discussions.

+
+
+
+ + + + diff --git a/apidoc/html/menu.js b/apidoc/html/menu.js new file mode 100644 index 0000000..717761d --- /dev/null +++ b/apidoc/html/menu.js @@ -0,0 +1,134 @@ +/* + @licstart The following is the entire license notice for the JavaScript code in this file. + + The MIT License (MIT) + + Copyright (C) 1997-2020 by Dimitri van Heesch + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software + and associated documentation files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, publish, distribute, + sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + @licend The above is the entire license notice for the JavaScript code in this file + */ +function initMenu(relPath,searchEnabled,serverSide,searchPage,search) { + function makeTree(data,relPath) { + let result=''; + if ('children' in data) { + result+='
    '; + for (let i in data.children) { + let url; + const link = data.children[i].url; + if (link.substring(0,1)=='^') { + url = link.substring(1); + } else { + url = relPath+link; + } + result+='
  • '+ + data.children[i].text+''+ + makeTree(data.children[i],relPath)+'
  • '; + } + result+='
'; + } + return result; + } + let searchBoxHtml; + if (searchEnabled) { + if (serverSide) { + searchBoxHtml='
'+ + '
'+ + '
 '+ + ''+ + '
'+ + '
'+ + '
'+ + '
'; + } else { + searchBoxHtml='
'+ + ''+ + ' '+ + ''+ + ''+ + ''+ + ''+ + ''+ + '
'; + } + } + + $('#main-nav').before('
'+ + ''+ + ''+ + '
'); + $('#main-nav').append(makeTree(menudata,relPath)); + $('#main-nav').children(':first').addClass('sm sm-dox').attr('id','main-menu'); + if (searchBoxHtml) { + $('#main-menu').append('
  • '); + } + const $mainMenuState = $('#main-menu-state'); + let prevWidth = 0; + if ($mainMenuState.length) { + const initResizableIfExists = function() { + if (typeof initResizable==='function') initResizable(); + } + // animate mobile menu + $mainMenuState.change(function() { + const $menu = $('#main-menu'); + let options = { duration: 250, step: initResizableIfExists }; + if (this.checked) { + options['complete'] = () => $menu.css('display', 'block'); + $menu.hide().slideDown(options); + } else { + options['complete'] = () => $menu.css('display', 'none'); + $menu.show().slideUp(options); + } + }); + // set default menu visibility + const resetState = function() { + const $menu = $('#main-menu'); + const newWidth = $(window).outerWidth(); + if (newWidth!=prevWidth) { + if ($(window).outerWidth()<768) { + $mainMenuState.prop('checked',false); $menu.hide(); + $('#searchBoxPos1').html(searchBoxHtml); + $('#searchBoxPos2').hide(); + } else { + $menu.show(); + $('#searchBoxPos1').empty(); + $('#searchBoxPos2').html(searchBoxHtml); + $('#searchBoxPos2').show(); + } + if (typeof searchBox!=='undefined') { + searchBox.CloseResultsWindow(); + } + prevWidth = newWidth; + } + } + $(window).ready(function() { resetState(); initResizableIfExists(); }); + $(window).resize(resetState); + } + $('#main-menu').smartmenus(); +} +/* @license-end */ diff --git a/apidoc/html/menudata.js b/apidoc/html/menudata.js new file mode 100644 index 0000000..de4526c --- /dev/null +++ b/apidoc/html/menudata.js @@ -0,0 +1,54 @@ +/* + @licstart The following is the entire license notice for the JavaScript code in this file. + + The MIT License (MIT) + + Copyright (C) 1997-2020 by Dimitri van Heesch + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software + and associated documentation files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, publish, distribute, + sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + @licend The above is the entire license notice for the JavaScript code in this file +*/ +var menudata={children:[ +{text:"Main Page",url:"index.html"}, +{text:"Related Pages",url:"pages.html"}, +{text:"Data Structures",url:"annotated.html",children:[ +{text:"Data Structures",url:"annotated.html"}, +{text:"Data Structure Index",url:"classes.html"}, +{text:"Data Fields",url:"functions.html",children:[ +{text:"All",url:"functions.html"}, +{text:"Variables",url:"functions_vars.html"}]}]}, +{text:"Files",url:"files.html",children:[ +{text:"File List",url:"files.html"}, +{text:"Globals",url:"globals.html",children:[ +{text:"All",url:"globals.html",children:[ +{text:"_",url:"globals.html#index__5F"}, +{text:"g",url:"globals_g.html#index_g"}, +{text:"h",url:"globals_h.html#index_h"}, +{text:"m",url:"globals_m.html#index_m"}, +{text:"r",url:"globals_r.html#index_r"}, +{text:"s",url:"globals_s.html#index_s"}, +{text:"x",url:"globals_x.html#index_x"}]}, +{text:"Functions",url:"globals_func.html",children:[ +{text:"s",url:"globals_func.html#index_s"}, +{text:"x",url:"globals_func_x.html#index_x"}]}, +{text:"Variables",url:"globals_vars.html"}, +{text:"Macros",url:"globals_defs.html",children:[ +{text:"_",url:"globals_defs.html#index__5F"}, +{text:"m",url:"globals_defs.html#index_m"}, +{text:"r",url:"globals_defs.html#index_r"}, +{text:"s",url:"globals_defs.html#index_s"}, +{text:"x",url:"globals_defs.html#index_x"}]}]}]}]} diff --git a/apidoc/html/minus.svg b/apidoc/html/minus.svg new file mode 100644 index 0000000..f70d0c1 --- /dev/null +++ b/apidoc/html/minus.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/apidoc/html/minusd.svg b/apidoc/html/minusd.svg new file mode 100644 index 0000000..5f8e879 --- /dev/null +++ b/apidoc/html/minusd.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/apidoc/html/nav_f.png b/apidoc/html/nav_f.png new file mode 100644 index 0000000000000000000000000000000000000000..5a578e8a4a441cf10599358c79078e1a7bf0f043 GIT binary patch literal 130 zcmeAS@N?(olHy`uVBq!ia0vp^j6iI`!2~2XGqLUlQl6eJjv*C{Z|@rN9WdZvcF4GY zT1a8Shr(lCa;vpo3FmD{{olCj_d2Z`)rX_Fjf9n$p3QmiE+K8fDuZJTf;&52h^N^- eD=)uQUn4Kbuh89`A`t^Ll)=;0&t;ucLK6U-;46{< literal 0 HcmV?d00001 diff --git a/apidoc/html/nav_fd.png b/apidoc/html/nav_fd.png new file mode 100644 index 0000000000000000000000000000000000000000..b1140961d5b2613fb6385b6d7074e8268c743e0e GIT binary patch literal 132 zcmeAS@N?(olHy`uVBq!ia0vp^j6iI`!2~2XGqLUlQr?~}jv*C{Z|@%DJz&7W?2r*( z!^9$VE#d!5t)G#hf$lrnb*tH5z1zJi;XQA*?g^g`jv2*GyPIb=t~w;a?D9luQT&Xb hGw$Eb{Qt3*;k7jDbbpPic|cREuKz6T0x9)$^>bP0l+XkKNirCq literal 0 HcmV?d00001 diff --git a/apidoc/html/nav_hd.png b/apidoc/html/nav_hd.png new file mode 100644 index 0000000000000000000000000000000000000000..12c356c6c77ab368246ab46f368f1b1d02518f65 GIT binary patch literal 98 zcmeAS@N?(olHy`uVBq!ia0vp^j6lr8!2~3AUOE6t22D>F$B+ufw|Bic860?+FFJjm wDDdBJdfQgR4|=0 ? varName.substring(i+1) : varName; + return eval(n.replace(/-/g,'_')); + } + + const stripPath = function(uri) { + return uri.substring(uri.lastIndexOf('/')+1); + } + + const stripPath2 = function(uri) { + const i = uri.lastIndexOf('/'); + const s = uri.substring(i+1); + const m = uri.substring(0,i+1).match(/\/d\w\/d\w\w\/$/); + return m ? uri.substring(i-6) : s; + } + + const hashValue = function() { + return $(location).attr('hash').substring(1).replace(/[^\w-]/g,''); + } + + const hashUrl = function() { + return '#'+hashValue(); + } + + const pathName = function() { + return $(location).attr('pathname').replace(/[^-A-Za-z0-9+&@#/%?=~_|!:,.;()]/g, ''); + } + + const storeLink = function(link) { + if (!$("#nav-sync").hasClass('sync')) { + Cookie.writeSetting(NAVPATH_COOKIE_NAME,link,0); + } + } + + const deleteLink = function() { + Cookie.eraseSetting(NAVPATH_COOKIE_NAME); + } + + const cachedLink = function() { + return Cookie.readSetting(NAVPATH_COOKIE_NAME,''); + } + + const getScript = function(scriptName,func) { + const head = document.getElementsByTagName("head")[0]; + const script = document.createElement('script'); + script.id = scriptName; + script.type = 'text/javascript'; + script.onload = func; + script.src = scriptName+'.js'; + head.appendChild(script); + } + + const createIndent = function(o,domNode,node) { + let level=-1; + let n = node; + while (n.parentNode) { level++; n=n.parentNode; } + if (node.childrenData) { + const imgNode = document.createElement("span"); + imgNode.className = 'arrow'; + imgNode.style.paddingLeft=(16*level).toString()+'px'; + imgNode.innerHTML=ARROW_RIGHT; + node.plus_img = imgNode; + node.expandToggle = document.createElement("a"); + node.expandToggle.href = "javascript:void(0)"; + node.expandToggle.onclick = function() { + if (node.expanded) { + $(node.getChildrenUL()).slideUp("fast"); + node.plus_img.innerHTML=ARROW_RIGHT; + node.expanded = false; + } else { + expandNode(o, node, false, true); + } + } + node.expandToggle.appendChild(imgNode); + domNode.appendChild(node.expandToggle); + } else { + let span = document.createElement("span"); + span.className = 'arrow'; + span.style.width = 16*(level+1)+'px'; + span.innerHTML = ' '; + domNode.appendChild(span); + } + } + + let animationInProgress = false; + + const gotoAnchor = function(anchor,aname) { + let pos, docContent = $('#doc-content'); + let ancParent = $(anchor.parent()); + if (ancParent.hasClass('memItemLeft') || ancParent.hasClass('memtitle') || + ancParent.hasClass('fieldname') || ancParent.hasClass('fieldtype') || + ancParent.is(':header')) { + pos = ancParent.position().top; + } else if (anchor.position()) { + pos = anchor.position().top; + } + if (pos) { + const dcOffset = docContent.offset().top; + const dcHeight = docContent.height(); + const dcScrHeight = docContent[0].scrollHeight + const dcScrTop = docContent.scrollTop(); + let dist = Math.abs(Math.min(pos-dcOffset,dcScrHeight-dcHeight-dcScrTop)); + animationInProgress = true; + docContent.animate({ + scrollTop: pos + dcScrTop - dcOffset + },Math.max(50,Math.min(500,dist)),function() { + window.location.href=aname; + animationInProgress=false; + }); + } + } + + const newNode = function(o, po, text, link, childrenData, lastNode) { + const node = { + children : [], + childrenData : childrenData, + depth : po.depth + 1, + relpath : po.relpath, + isLast : lastNode, + li : document.createElement("li"), + parentNode : po, + itemDiv : document.createElement("div"), + labelSpan : document.createElement("span"), + label : document.createTextNode(text), + expanded : false, + childrenUL : null, + getChildrenUL : function() { + if (!this.childrenUL) { + this.childrenUL = document.createElement("ul"); + this.childrenUL.className = "children_ul"; + this.childrenUL.style.display = "none"; + this.li.appendChild(node.childrenUL); + } + return node.childrenUL; + }, + }; + + node.itemDiv.className = "item"; + node.labelSpan.className = "label"; + createIndent(o,node.itemDiv,node); + node.itemDiv.appendChild(node.labelSpan); + node.li.appendChild(node.itemDiv); + + const a = document.createElement("a"); + node.labelSpan.appendChild(a); + po.getChildrenUL().appendChild(node.li); + a.appendChild(node.label); + if (link) { + let url; + if (link.substring(0,1)=='^') { + url = link.substring(1); + link = url; + } else { + url = node.relpath+link; + } + a.className = stripPath(link.replace('#',':')); + if (link.indexOf('#')!=-1) { + const aname = '#'+link.split('#')[1]; + const srcPage = stripPath(pathName()); + const targetPage = stripPath(link.split('#')[0]); + a.href = srcPage!=targetPage ? url : aname; + a.onclick = function() { + storeLink(link); + aPPar = $(a).parent().parent(); + if (!aPPar.hasClass('selected')) { + $('.item').removeClass('selected'); + $('.item').removeAttr('id'); + aPPar.addClass('selected'); + aPPar.attr('id','selected'); + } + const anchor = $(aname); + gotoAnchor(anchor,aname); + }; + } else { + a.href = url; + a.onclick = () => storeLink(link); + } + } else if (childrenData != null) { + a.className = "nolink"; + a.href = "javascript:void(0)"; + a.onclick = node.expandToggle.onclick; + } + return node; + } + + const showRoot = function() { + const headerHeight = $("#top").height(); + const footerHeight = $("#nav-path").height(); + const windowHeight = $(window).height() - headerHeight - footerHeight; + (function() { // retry until we can scroll to the selected item + try { + const navtree=$('#nav-tree'); + navtree.scrollTo('#selected',100,{offset:-windowHeight/2}); + } catch (err) { + setTimeout(arguments.callee, 0); + } + })(); + } + + const expandNode = function(o, node, imm, setFocus) { + if (node.childrenData && !node.expanded) { + if (typeof(node.childrenData)==='string') { + const varName = node.childrenData; + getScript(node.relpath+varName,function() { + node.childrenData = getData(varName); + expandNode(o, node, imm, setFocus); + }); + } else { + if (!node.childrenVisited) { + getNode(o, node); + } + $(node.getChildrenUL()).slideDown("fast"); + node.plus_img.innerHTML = ARROW_DOWN; + node.expanded = true; + if (setFocus) { + $(node.expandToggle).focus(); + } + } + } + } + + const glowEffect = function(n,duration) { + n.addClass('glow').delay(duration).queue(function(next) { + $(this).removeClass('glow');next(); + }); + } + + const highlightAnchor = function() { + const aname = hashUrl(); + const anchor = $(aname); + if (anchor.parent().attr('class')=='memItemLeft') { + let rows = $('.memberdecls tr[class$="'+hashValue()+'"]'); + glowEffect(rows.children(),300); // member without details + } else if (anchor.parent().attr('class')=='fieldname') { + glowEffect(anchor.parent().parent(),1000); // enum value + } else if (anchor.parent().attr('class')=='fieldtype') { + glowEffect(anchor.parent().parent(),1000); // struct field + } else if (anchor.parent().is(":header")) { + glowEffect(anchor.parent(),1000); // section header + } else { + glowEffect(anchor.next(),1000); // normal member + } + gotoAnchor(anchor,aname); + } + + const selectAndHighlight = function(hash,n) { + let a; + if (hash) { + const link=stripPath(pathName())+':'+hash.substring(1); + a=$('.item a[class$="'+link+'"]'); + } + if (a && a.length) { + a.parent().parent().addClass('selected'); + a.parent().parent().attr('id','selected'); + highlightAnchor(); + } else if (n) { + $(n.itemDiv).addClass('selected'); + $(n.itemDiv).attr('id','selected'); + } + let topOffset=5; + if ($('#nav-tree-contents .item:first').hasClass('selected')) { + topOffset+=25; + } + $('#nav-sync').css('top',topOffset+'px'); + showRoot(); + } + + const showNode = function(o, node, index, hash) { + if (node && node.childrenData) { + if (typeof(node.childrenData)==='string') { + const varName = node.childrenData; + getScript(node.relpath+varName,function() { + node.childrenData = getData(varName); + showNode(o,node,index,hash); + }); + } else { + if (!node.childrenVisited) { + getNode(o, node); + } + $(node.getChildrenUL()).css({'display':'block'}); + node.plus_img.innerHTML = ARROW_DOWN; + node.expanded = true; + const n = node.children[o.breadcrumbs[index]]; + if (index+11 ? '#'+parts[1].replace(/[^\w-]/g,'') : ''; + } + if (hash.match(/^#l\d+$/)) { + const anchor=$('a[name='+hash.substring(1)+']'); + glowEffect(anchor.parent(),1000); // line number + hash=''; // strip line number anchors + } + const url=root+hash; + let i=-1; + while (NAVTREEINDEX[i+1]<=url) i++; + if (i==-1) { i=0; root=NAVTREE[0][1]; } // fallback: show index + if (navTreeSubIndices[i]) { + gotoNode(o,i,root,hash,relpath) + } else { + getScript(relpath+'navtreeindex'+i,function() { + navTreeSubIndices[i] = eval('NAVTREEINDEX'+i); + if (navTreeSubIndices[i]) { + gotoNode(o,i,root,hash,relpath); + } + }); + } + } + + const showSyncOff = function(n,relpath) { + n.html(''); + } + + const showSyncOn = function(n,relpath) { + n.html(''); + } + + const o = { + toroot : toroot, + node : { + childrenData : NAVTREE, + children : [], + childrenUL : document.createElement("ul"), + getChildrenUL : function() { return this.childrenUL }, + li : document.getElementById("nav-tree-contents"), + depth : 0, + relpath : relpath, + expanded : false, + isLast : true, + plus_img : document.createElement("span"), + }, + }; + o.node.li.appendChild(o.node.childrenUL); + o.node.plus_img.className = 'arrow'; + o.node.plus_img.innerHTML = ARROW_RIGHT; + + const navSync = $('#nav-sync'); + if (cachedLink()) { + showSyncOff(navSync,relpath); + navSync.removeClass('sync'); + } else { + showSyncOn(navSync,relpath); + } + + navSync.click(() => { + const navSync = $('#nav-sync'); + if (navSync.hasClass('sync')) { + navSync.removeClass('sync'); + showSyncOff(navSync,relpath); + storeLink(stripPath2(pathName())+hashUrl()); + } else { + navSync.addClass('sync'); + showSyncOn(navSync,relpath); + deleteLink(); + } + }); + + navTo(o,toroot,hashUrl(),relpath); + showRoot(); + + $(window).bind('hashchange', () => { + if (window.location.hash && window.location.hash.length>1) { + let a; + if ($(location).attr('hash')) { + const clslink=stripPath(pathName())+':'+hashValue(); + a=$('.item a[class$="'+clslink.replace(/1|%O$WD@{VR-P`7Ar*{o?>cfFFyLT0a8doY z!2UZIob*&rS{`q775~CnF#E+jcE3%ln9A!3=;PL_{miWQc~cmUuVDw8 O!r + + + + + + +smax-clib: Related Pages + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + +
    +
    smax-clib v0.9 +
    +
    A C/C++ client library for SMA-X
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    +
    Related Pages
    +
    +
    +
    Here is a list of all related documentation pages:
    +
    +
    + + + + diff --git a/apidoc/html/plugin.xml b/apidoc/html/plugin.xml new file mode 100644 index 0000000..11b4650 --- /dev/null +++ b/apidoc/html/plugin.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/apidoc/html/plus.svg b/apidoc/html/plus.svg new file mode 100644 index 0000000..0752016 --- /dev/null +++ b/apidoc/html/plus.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/apidoc/html/plusd.svg b/apidoc/html/plusd.svg new file mode 100644 index 0000000..0c65bfe --- /dev/null +++ b/apidoc/html/plusd.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/apidoc/html/resize.js b/apidoc/html/resize.js new file mode 100644 index 0000000..6ad2ae8 --- /dev/null +++ b/apidoc/html/resize.js @@ -0,0 +1,109 @@ +/* + @licstart The following is the entire license notice for the JavaScript code in this file. + + The MIT License (MIT) + + Copyright (C) 1997-2020 by Dimitri van Heesch + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software + and associated documentation files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, publish, distribute, + sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + @licend The above is the entire license notice for the JavaScript code in this file + */ + +function initResizable() { + let sidenav,navtree,content,header,footer,barWidth=6; + const RESIZE_COOKIE_NAME = ''+'width'; + + function resizeWidth() { + const sidenavWidth = $(sidenav).outerWidth(); + content.css({marginLeft:parseInt(sidenavWidth)+"px"}); + if (typeof page_layout!=='undefined' && page_layout==1) { + footer.css({marginLeft:parseInt(sidenavWidth)+"px"}); + } + Cookie.writeSetting(RESIZE_COOKIE_NAME,sidenavWidth-barWidth); + } + + function restoreWidth(navWidth) { + content.css({marginLeft:parseInt(navWidth)+barWidth+"px"}); + if (typeof page_layout!=='undefined' && page_layout==1) { + footer.css({marginLeft:parseInt(navWidth)+barWidth+"px"}); + } + sidenav.css({width:navWidth + "px"}); + } + + function resizeHeight() { + const headerHeight = header.outerHeight(); + const footerHeight = footer.outerHeight(); + const windowHeight = $(window).height(); + let contentHeight,navtreeHeight,sideNavHeight; + if (typeof page_layout==='undefined' || page_layout==0) { /* DISABLE_INDEX=NO */ + contentHeight = windowHeight - headerHeight - footerHeight; + navtreeHeight = contentHeight; + sideNavHeight = contentHeight; + } else if (page_layout==1) { /* DISABLE_INDEX=YES */ + contentHeight = windowHeight - footerHeight; + navtreeHeight = windowHeight - headerHeight; + sideNavHeight = windowHeight; + } + content.css({height:contentHeight + "px"}); + navtree.css({height:navtreeHeight + "px"}); + sidenav.css({height:sideNavHeight + "px"}); + if (location.hash.slice(1)) { + (document.getElementById(location.hash.slice(1))||document.body).scrollIntoView(); + } + } + + function collapseExpand() { + let newWidth; + if (sidenav.width()>0) { + newWidth=0; + } else { + const width = Cookie.readSetting(RESIZE_COOKIE_NAME,250); + newWidth = (width>250 && width<$(window).width()) ? width : 250; + } + restoreWidth(newWidth); + const sidenavWidth = $(sidenav).outerWidth(); + Cookie.writeSetting(RESIZE_COOKIE_NAME,sidenavWidth-barWidth); + } + + header = $("#top"); + sidenav = $("#side-nav"); + content = $("#doc-content"); + navtree = $("#nav-tree"); + footer = $("#nav-path"); + $(".side-nav-resizable").resizable({resize: () => resizeWidth() }); + $(sidenav).resizable({ minWidth: 0 }); + $(window).resize(() => resizeHeight()); + const device = navigator.userAgent.toLowerCase(); + const touch_device = device.match(/(iphone|ipod|ipad|android)/); + if (touch_device) { /* wider split bar for touch only devices */ + $(sidenav).css({ paddingRight:'20px' }); + $('.ui-resizable-e').css({ width:'20px' }); + $('#nav-sync').css({ right:'34px' }); + barWidth=20; + } + const width = Cookie.readSetting(RESIZE_COOKIE_NAME,250); + if (width) { restoreWidth(width); } else { resizeWidth(); } + resizeHeight(); + const url = location.href; + const i=url.indexOf("#"); + if (i>=0) window.location.hash=url.substr(i); + const _preventDefault = (evt) => evt.preventDefault(); + $("#splitbar").bind("dragstart", _preventDefault).bind("selectstart", _preventDefault); + $(".ui-resizable-handle").dblclick(collapseExpand); + $(window).on('load',resizeHeight); +} +/* @license-end */ diff --git a/apidoc/html/search/all_0.js b/apidoc/html/search/all_0.js new file mode 100644 index 0000000..948d04c --- /dev/null +++ b/apidoc/html/search/all_0.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['_5f_5fxchange_5finternal_5fapi_5f_5f_0',['__XCHANGE_INTERNAL_API__',['../smax-private_8h.html#ac36bd75f87a1614fb477a0fbcd5df1f3',1,'smax-private.h']]] +]; diff --git a/apidoc/html/search/all_1.js b/apidoc/html/search/all_1.js new file mode 100644 index 0000000..34934e0 --- /dev/null +++ b/apidoc/html/search/all_1.js @@ -0,0 +1,9 @@ +var searchData= +[ + ['and_20pulling_20data_0',['Sharing and pulling data',['../index.html#autotoc_md16',1,'']]], + ['and_20sizes_1',['Flexible types and sizes',['../index.html#autotoc_md19',1,'']]], + ['and_20update_20handling_2',['Custom notifications and update handling',['../index.html#autotoc_md31',1,'']]], + ['and_20waiting_3',['Synchronization points and waiting',['../index.html#autotoc_md27',1,'']]], + ['arrays_4',['Arrays',['../index.html#autotoc_md21',1,'']]], + ['axis_5',['axis',['../structXCoordinateSystem.html#a5275f744c5bfc9a13b31a19c7ec5346c',1,'XCoordinateSystem']]] +]; diff --git a/apidoc/html/search/all_10.js b/apidoc/html/search/all_10.js new file mode 100644 index 0000000..eb75219 --- /dev/null +++ b/apidoc/html/search/all_10.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['redisx_0',['Contributing to RedisX',['../md_CONTRIBUTING.html',1,'']]], + ['refindex_1',['refIndex',['../structXCoordinateAxis.html#ad191af99a874bc633c0834d247427ea8',1,'XCoordinateAxis']]], + ['refvalue_2',['refValue',['../structXCoordinateAxis.html#ad56f22fc3fbf9639a29ed9f174c67ec2',1,'XCoordinateAxis']]], + ['releaseid_3',['RELEASEID',['../smax-private_8h.html#acb5965a4e56d8d90d76002bef3207ef9',1,'smax-private.h']]] +]; diff --git a/apidoc/html/search/all_11.js b/apidoc/html/search/all_11.js new file mode 100644 index 0000000..24cccfd --- /dev/null +++ b/apidoc/html/search/all_11.js @@ -0,0 +1,202 @@ +var searchData= +[ + ['scalar_20quantities_0',['Scalar quantities',['../index.html#autotoc_md20',1,'']]], + ['serial_1',['serial',['../structXMeta.html#a4f4017ce7a39a4da2ed1cf8c4dc7de3f',1,'XMeta']]], + ['sharing_20and_20pulling_20data_2',['Sharing and pulling data',['../index.html#autotoc_md16',1,'']]], + ['sizes_3',['Flexible types and sizes',['../index.html#autotoc_md19',1,'']]], + ['sma_20x_4',['Connecting to / disconnecting from SMA-X',['../index.html#autotoc_md13',1,'']]], + ['sma_20x_20c_20library_5',['Building the SMA-X C library',['../index.html#autotoc_md9',1,'']]], + ['smax_20clib_6',['smax-clib',['../index.html',1,'']]], + ['smax_2deasy_2ec_7',['smax-easy.c',['../smax-easy_8c.html',1,'']]], + ['smax_2dlazy_2ec_8',['smax-lazy.c',['../smax-lazy_8c.html',1,'']]], + ['smax_2dmessages_2ec_9',['smax-messages.c',['../smax-messages_8c.html',1,'']]], + ['smax_2dmeta_2ec_10',['smax-meta.c',['../smax-meta_8c.html',1,'']]], + ['smax_2dprivate_2eh_11',['smax-private.h',['../smax-private_8h.html',1,'']]], + ['smax_2dqueue_2ec_12',['smax-queue.c',['../smax-queue_8c.html',1,'']]], + ['smax_2dresilient_2ec_13',['smax-resilient.c',['../smax-resilient_8c.html',1,'']]], + ['smax_2dutil_2ec_14',['smax-util.c',['../smax-util_8c.html',1,'']]], + ['smax_2ec_15',['smax.c',['../smax_8c.html',1,'']]], + ['smax_2eh_16',['smax.h',['../smax_8h.html',1,'']]], + ['smax2xfield_17',['smax2xField',['../smax-util_8c.html#abfe751f22aa718133911ffdee848f64a',1,'smax2xField(XField *f): smax-util.c'],['../smax_8h.html#abfe751f22aa718133911ffdee848f64a',1,'smax2xField(XField *f): smax-util.c']]], + ['smax2xstruct_18',['smax2xStruct',['../smax-util_8c.html#a50fef3b0daf40f7de6f52b05abd2963c',1,'smax2xStruct(XStructure *s): smax-util.c'],['../smax_8h.html#a50fef3b0daf40f7de6f52b05abd2963c',1,'smax2xStruct(XStructure *s): smax-util.c']]], + ['smax_5fdefault_5fhostname_19',['SMAX_DEFAULT_HOSTNAME',['../smax_8h.html#a0fe198db49d87d696072c261e49f7cce',1,'smax.h']]], + ['smax_5fdefault_5fmax_5fqueued_20',['SMAX_DEFAULT_MAX_QUEUED',['../smax_8h.html#aeb7304db99c63c3f0a10fca90e74abe4',1,'smax.h']]], + ['smax_5fdefault_5fpipeline_5fenabled_21',['SMAX_DEFAULT_PIPELINE_ENABLED',['../smax_8h.html#aac2af1cdc522f5e3acc75edf7d41b267',1,'smax.h']]], + ['smax_5fdims_22',['SMAX_DIMS',['../smax_8h.html#a59b5959fb0859d4dbe98408f2cc2f1d0',1,'smax.h']]], + ['smax_5fmsg_5fdebug_23',['SMAX_MSG_DEBUG',['../smax_8h.html#a8b3859624653c39bebe617c91567ad0d',1,'smax.h']]], + ['smax_5fmsg_5fdetail_24',['SMAX_MSG_DETAIL',['../smax_8h.html#a06ee6433a1353c48c2c8ce5e8fd6631c',1,'smax.h']]], + ['smax_5fmsg_5ferror_25',['SMAX_MSG_ERROR',['../smax_8h.html#aeae00b97b43f8563939cd9ebcfdc4c62',1,'smax.h']]], + ['smax_5fmsg_5finfo_26',['SMAX_MSG_INFO',['../smax_8h.html#a539edc8fa4545dbe7c388e8f0644f6c0',1,'smax.h']]], + ['smax_5fmsg_5fprogress_27',['SMAX_MSG_PROGRESS',['../smax_8h.html#a52b656c8731bc8ef9ef83d5307fd157e',1,'smax.h']]], + ['smax_5fmsg_5fstatus_28',['SMAX_MSG_STATUS',['../smax_8h.html#a3168f34d2cd8afae9e9f9848ee684597',1,'smax.h']]], + ['smax_5fmsg_5fwarning_29',['SMAX_MSG_WARNING',['../smax_8h.html#a007762d6503940a6e287efab02083276',1,'smax.h']]], + ['smax_5forigin_5flength_30',['SMAX_ORIGIN_LENGTH',['../smax_8h.html#a012a406ddc842479b2aefaa987e6c591',1,'smax.h']]], + ['smax_5forigins_31',['SMAX_ORIGINS',['../smax_8h.html#a30235420adcb90ff2d2a0f6085a23427',1,'smax.h']]], + ['smax_5fpipe_5fread_5ftimeout_5fmillis_32',['SMAX_PIPE_READ_TIMEOUT_MILLIS',['../smax_8h.html#a38eb97e64eaf65a5273fa6d6ff765a93',1,'smax.h']]], + ['smax_5freads_33',['SMAX_READS',['../smax_8h.html#ab986e2d3951e64cb3300a62c1f010551',1,'smax.h']]], + ['smax_5freconnect_5fretry_5fseconds_34',['SMAX_RECONNECT_RETRY_SECONDS',['../smax_8h.html#a3e9baa458ae59eb26923d6ce863bf700',1,'smax.h']]], + ['smax_5frestore_5fqueue_5fon_5freconnect_35',['SMAX_RESTORE_QUEUE_ON_RECONNECT',['../smax_8h.html#a2f111386ac4b76cd858de99478720b29',1,'smax.h']]], + ['smax_5fscripts_36',['SMAX_SCRIPTS',['../smax_8h.html#a23dedcaf9704eed433cf3920af5e5e1c',1,'smax.h']]], + ['smax_5ftimestamps_37',['SMAX_TIMESTAMPS',['../smax_8h.html#ab5e13a0e5a3b57b087a2c875a01317b4',1,'smax.h']]], + ['smax_5ftypes_38',['SMAX_TYPES',['../smax_8h.html#a6933f3dab1f1de96cca777d65cdd5c40',1,'smax.h']]], + ['smax_5fupdates_39',['SMAX_UPDATES',['../smax_8h.html#a341a9de00cacd431dcd8ac8622b0bf7d',1,'smax.h']]], + ['smax_5fupdates_5flength_40',['SMAX_UPDATES_LENGTH',['../smax_8h.html#ac59ccff9171d5b4e9545fd1ceef027b8',1,'smax.h']]], + ['smax_5fupdates_5froot_41',['SMAX_UPDATES_ROOT',['../smax_8h.html#abfefd74fb72fc51e4577d1fa5fa832f4',1,'smax.h']]], + ['smax_5fwrites_42',['SMAX_WRITES',['../smax_8h.html#af6088c6c91a1f0089000288f0214f67c',1,'smax.h']]], + ['smaxaddconnecthook_43',['smaxAddConnectHook',['../smax_8c.html#ad63c425cc3affdf8bc803c7ff8dd6e30',1,'smaxAddConnectHook(void(*setupCall)(void)): smax.c'],['../smax_8h.html#ad63c425cc3affdf8bc803c7ff8dd6e30',1,'smaxAddConnectHook(void(*setupCall)(void)): smax.c']]], + ['smaxadddefaultmessageprocessor_44',['smaxAddDefaultMessageProcessor',['../smax-messages_8c.html#aa3e777f85e81ffb9b02dc8cc3d124a94',1,'smaxAddDefaultMessageProcessor(const char *host, const char *prog, const char *type): smax-messages.c'],['../smax_8h.html#aa3e777f85e81ffb9b02dc8cc3d124a94',1,'smaxAddDefaultMessageProcessor(const char *host, const char *prog, const char *type): smax-messages.c']]], + ['smaxadddisconnecthook_45',['smaxAddDisconnectHook',['../smax_8c.html#a65ae161b28cfe4369709fae1d3ea678c',1,'smaxAddDisconnectHook(void(*cleanupCall)(void)): smax.c'],['../smax_8h.html#a65ae161b28cfe4369709fae1d3ea678c',1,'smaxAddDisconnectHook(void(*cleanupCall)(void)): smax.c']]], + ['smaxaddmessageprocessor_46',['smaxAddMessageProcessor',['../smax-messages_8c.html#abaa2573fb8e85e8359c8853647c38f2f',1,'smaxAddMessageProcessor(const char *host, const char *prog, const char *type, void(*f)(XMessage *)): smax-messages.c'],['../smax_8h.html#abaa2573fb8e85e8359c8853647c38f2f',1,'smaxAddMessageProcessor(const char *host, const char *prog, const char *type, void(*f)(XMessage *)): smax-messages.c']]], + ['smaxaddsubscriber_47',['smaxAddSubscriber',['../smax_8c.html#a827dd87397943f3384605f87116b630c',1,'smaxAddSubscriber(const char *idStem, RedisSubscriberCall f): smax.c'],['../smax_8h.html#a1714cac6dfa55917edecd0028e6da64c',1,'smaxAddSubscriber(const char *stem, RedisSubscriberCall f): smax.c']]], + ['smaxconnect_48',['smaxConnect',['../smax_8c.html#a146fb2ed8512919dc91ecad6d08c74d1',1,'smaxConnect(): smax.c'],['../smax_8h.html#a146fb2ed8512919dc91ecad6d08c74d1',1,'smaxConnect(): smax.c']]], + ['smaxconnectto_49',['smaxConnectTo',['../smax_8c.html#ad960c22b119ff2493a319945a9dd55a5',1,'smaxConnectTo(const char *server): smax.c'],['../smax_8h.html#ad960c22b119ff2493a319945a9dd55a5',1,'smaxConnectTo(const char *server): smax.c']]], + ['smaxcreate1dfield_50',['smaxCreate1DField',['../smax-easy_8c.html#afba357d35d2a1f13d0cf06f5ff708a99',1,'smaxCreate1DField(const char *name, XType type, int size, const void *value): smax-easy.c'],['../smax_8h.html#afba357d35d2a1f13d0cf06f5ff708a99',1,'smaxCreate1DField(const char *name, XType type, int size, const void *value): smax-easy.c']]], + ['smaxcreatebooleanfield_51',['smaxCreateBooleanField',['../smax-easy_8c.html#a13e357c3f20c0799fba6bc6c2a16c520',1,'smaxCreateBooleanField(const char *name, boolean value): smax-easy.c'],['../smax_8h.html#a13e357c3f20c0799fba6bc6c2a16c520',1,'smaxCreateBooleanField(const char *name, boolean value): smax-easy.c']]], + ['smaxcreatecoordinatesystem_52',['smaxCreateCoordinateSystem',['../smax-meta_8c.html#a1d977e7e9eb45f9ce6cc338fdde9bd8f',1,'smaxCreateCoordinateSystem(int nAxis): smax-meta.c'],['../smax_8h.html#a1d977e7e9eb45f9ce6cc338fdde9bd8f',1,'smaxCreateCoordinateSystem(int nAxis): smax-meta.c']]], + ['smaxcreatedoublefield_53',['smaxCreateDoubleField',['../smax-easy_8c.html#afa9c9ec0f47236c0c560eee724b809d6',1,'smaxCreateDoubleField(const char *name, double value): smax-easy.c'],['../smax_8h.html#afa9c9ec0f47236c0c560eee724b809d6',1,'smaxCreateDoubleField(const char *name, double value): smax-easy.c']]], + ['smaxcreatefield_54',['smaxCreateField',['../smax-util_8c.html#a9871356984c4794a9f9caa3870dc6794',1,'smaxCreateField(const char *name, XType type, int ndim, const int *sizes, const void *value): smax-util.c'],['../smax_8h.html#a9871356984c4794a9f9caa3870dc6794',1,'smaxCreateField(const char *name, XType type, int ndim, const int *sizes, const void *value): smax-util.c']]], + ['smaxcreateintfield_55',['smaxCreateIntField',['../smax-easy_8c.html#afcb9ce5f154eef8eccdb0930ec4d613d',1,'smaxCreateIntField(const char *name, int value): smax-easy.c'],['../smax_8h.html#afcb9ce5f154eef8eccdb0930ec4d613d',1,'smaxCreateIntField(const char *name, int value): smax-easy.c']]], + ['smaxcreatelongfield_56',['smaxCreateLongField',['../smax-easy_8c.html#a23b55eae1ce68356073ea5b191f915e5',1,'smaxCreateLongField(const char *name, long long value): smax-easy.c'],['../smax_8h.html#a23b55eae1ce68356073ea5b191f915e5',1,'smaxCreateLongField(const char *name, long long value): smax-easy.c']]], + ['smaxcreatemeta_57',['smaxCreateMeta',['../smax-util_8c.html#a48decaf10195b2f21fa77d8ea9b94fff',1,'smaxCreateMeta(): smax-util.c'],['../smax_8h.html#a48decaf10195b2f21fa77d8ea9b94fff',1,'smaxCreateMeta(): smax-util.c']]], + ['smaxcreatescalarfield_58',['smaxCreateScalarField',['../smax-easy_8c.html#a61a3760159e6867cdb55b5995435633c',1,'smaxCreateScalarField(const char *name, XType type, const void *value): smax-easy.c'],['../smax_8h.html#a61a3760159e6867cdb55b5995435633c',1,'smaxCreateScalarField(const char *name, XType type, const void *value): smax-easy.c']]], + ['smaxcreatestringfield_59',['smaxCreateStringField',['../smax-easy_8c.html#aa5c7661e29f4f1ba62f457c7138f2654',1,'smaxCreateStringField(const char *name, const char *value): smax-easy.c'],['../smax_8h.html#aa5c7661e29f4f1ba62f457c7138f2654',1,'smaxCreateStringField(const char *name, const char *value): smax-easy.c']]], + ['smaxcreatesyncpoint_60',['smaxCreateSyncPoint',['../smax-queue_8c.html#a30e2e1eb462ed2274a55016830b9abc1',1,'smaxCreateSyncPoint(): smax-queue.c'],['../smax_8h.html#a30e2e1eb462ed2274a55016830b9abc1',1,'smaxCreateSyncPoint(): smax-queue.c']]], + ['smaxdeletepattern_61',['smaxDeletePattern',['../smax-util_8c.html#a6c116311d61874554f98332831ad872b',1,'smaxDeletePattern(const char *pattern): smax-util.c'],['../smax_8h.html#a6c116311d61874554f98332831ad872b',1,'smaxDeletePattern(const char *pattern): smax-util.c']]], + ['smaxdestroycoordinatesystem_62',['smaxDestroyCoordinateSystem',['../smax-meta_8c.html#a92cf6cd3b3f123e21a1cee437f87126d',1,'smaxDestroyCoordinateSystem(XCoordinateSystem *coords): smax-meta.c'],['../smax_8h.html#a92cf6cd3b3f123e21a1cee437f87126d',1,'smaxDestroyCoordinateSystem(XCoordinateSystem *coords): smax-meta.c']]], + ['smaxdestroysyncpoint_63',['smaxDestroySyncPoint',['../smax-queue_8c.html#a012860edbebf45f24b1b08c02a37847b',1,'smaxDestroySyncPoint(XSyncPoint *s): smax-queue.c'],['../smax_8h.html#a97ace8424abf924b8ae0397ae83177f2',1,'smaxDestroySyncPoint(XSyncPoint *sync): smax-queue.c']]], + ['smaxdisconnect_64',['smaxDisconnect',['../smax_8c.html#a9d1e6ffa837d3582a8165e326cc44bea',1,'smaxDisconnect(): smax.c'],['../smax_8h.html#a9d1e6ffa837d3582a8165e326cc44bea',1,'smaxDisconnect(): smax.c']]], + ['smaxerror_65',['smaxError',['../smax-util_8c.html#aefcb16af3690ffe9c77224af6b394869',1,'smaxError(const char *func, int errorCode): smax-util.c'],['../smax_8h.html#aefcb16af3690ffe9c77224af6b394869',1,'smaxError(const char *func, int errorCode): smax-util.c']]], + ['smaxerrordescription_66',['smaxErrorDescription',['../smax-util_8c.html#a51856e0dc0261f8e44c8635d31d6193c',1,'smaxErrorDescription(int code): smax-util.c'],['../smax_8h.html#a51856e0dc0261f8e44c8635d31d6193c',1,'smaxErrorDescription(int code): smax-util.c']]], + ['smaxgetarrayfield_67',['smaxGetArrayField',['../smax-easy_8c.html#a10525c664231e85f3cd9a592915b8919',1,'smaxGetArrayField(const XStructure *s, const char *name, void *dst, XType type, int count): smax-easy.c'],['../smax_8h.html#a10525c664231e85f3cd9a592915b8919',1,'smaxGetArrayField(const XStructure *s, const char *name, void *dst, XType type, int count): smax-easy.c']]], + ['smaxgetbooleanfield_68',['smaxGetBooleanField',['../smax-easy_8c.html#a555c133ddd7aee3cf481f9e5e15e3d43',1,'smaxGetBooleanField(const XStructure *s, const char *name, boolean defaultValue): smax-easy.c'],['../smax_8h.html#a555c133ddd7aee3cf481f9e5e15e3d43',1,'smaxGetBooleanField(const XStructure *s, const char *name, boolean defaultValue): smax-easy.c']]], + ['smaxgetcoordinateaxis_69',['smaxGetCoordinateAxis',['../smax-meta_8c.html#a349dc6fe14a2031d679e29804d82d570',1,'smaxGetCoordinateAxis(const char *id, int n): smax-meta.c'],['../smax_8h.html#a349dc6fe14a2031d679e29804d82d570',1,'smaxGetCoordinateAxis(const char *id, int n): smax-meta.c']]], + ['smaxgetcoordinatesystem_70',['smaxGetCoordinateSystem',['../smax-meta_8c.html#a2920bd71f9d340422e0b1b0db4bb3201',1,'smaxGetCoordinateSystem(const char *table, const char *key): smax-meta.c'],['../smax_8h.html#a2920bd71f9d340422e0b1b0db4bb3201',1,'smaxGetCoordinateSystem(const char *table, const char *key): smax-meta.c']]], + ['smaxgetdescription_71',['smaxGetDescription',['../smax-meta_8c.html#ad7ef601ffd5fbcae7b2c05be6f6bc302',1,'smaxGetDescription(const char *table, const char *key): smax-meta.c'],['../smax_8h.html#ad7ef601ffd5fbcae7b2c05be6f6bc302',1,'smaxGetDescription(const char *table, const char *key): smax-meta.c']]], + ['smaxgetdoublefield_72',['smaxGetDoubleField',['../smax-easy_8c.html#ab7c45d4512c22c24153763aa9e227b68',1,'smaxGetDoubleField(const XStructure *s, const char *name, double defaultValue): smax-easy.c'],['../smax_8h.html#ab7c45d4512c22c24153763aa9e227b68',1,'smaxGetDoubleField(const XStructure *s, const char *name, double defaultValue): smax-easy.c']]], + ['smaxgethostname_73',['smaxGetHostName',['../smax_8c.html#ac704fea3e664905af780d2566e3c74b6',1,'smaxGetHostName(): smax.c'],['../smax_8h.html#ac704fea3e664905af780d2566e3c74b6',1,'smaxGetHostName(): smax.c']]], + ['smaxgetkeys_74',['smaxGetKeys',['../smax_8c.html#a2544d1fa602e812004e1d68500024ae0',1,'smaxGetKeys(const char *table, int *n): smax.c'],['../smax_8h.html#a2544d1fa602e812004e1d68500024ae0',1,'smaxGetKeys(const char *table, int *n): smax.c']]], + ['smaxgetlazycached_75',['smaxGetLazyCached',['../smax-lazy_8c.html#a42c08f13c70400dc1225d4097342ded0',1,'smaxGetLazyCached(const char *table, const char *key, XType type, int count, void *value, XMeta *meta): smax-lazy.c'],['../smax_8h.html#a42c08f13c70400dc1225d4097342ded0',1,'smaxGetLazyCached(const char *table, const char *key, XType type, int count, void *value, XMeta *meta): smax-lazy.c']]], + ['smaxgetlazyupdatecount_76',['smaxGetLazyUpdateCount',['../smax-lazy_8c.html#aeca4aa02259278b240e4131f7edea816',1,'smaxGetLazyUpdateCount(const char *table, const char *key): smax-lazy.c'],['../smax_8h.html#aeca4aa02259278b240e4131f7edea816',1,'smaxGetLazyUpdateCount(const char *table, const char *key): smax-lazy.c']]], + ['smaxgetlongfield_77',['smaxGetLongField',['../smax-easy_8c.html#a8035211bd1fe17551a1517560b2547c4',1,'smaxGetLongField(const XStructure *s, const char *name, long long defaultValue): smax-easy.c'],['../smax_8h.html#a8035211bd1fe17551a1517560b2547c4',1,'smaxGetLongField(const XStructure *s, const char *name, long long defaultValue): smax-easy.c']]], + ['smaxgetmetacount_78',['smaxGetMetaCount',['../smax-util_8c.html#ac6d47a508669e4ee215cb72c5366fc52',1,'smaxGetMetaCount(const XMeta *m): smax-util.c'],['../smax_8h.html#ac6d47a508669e4ee215cb72c5366fc52',1,'smaxGetMetaCount(const XMeta *m): smax-util.c']]], + ['smaxgetprogramid_79',['smaxGetProgramID',['../smax_8c.html#abc07a7599e0bac1be15bbcb6b63d4710',1,'smaxGetProgramID(): smax.c'],['../smax_8h.html#abc07a7599e0bac1be15bbcb6b63d4710',1,'smaxGetProgramID(): smax.c']]], + ['smaxgetrawfield_80',['smaxGetRawField',['../smax-easy_8c.html#ada517cdb7737bb38695e2a343123583b',1,'smaxGetRawField(const XStructure *s, const char *name, char *defaultValue): smax-easy.c'],['../smax_8h.html#ada517cdb7737bb38695e2a343123583b',1,'smaxGetRawField(const XStructure *s, const char *name, char *defaultValue): smax-easy.c']]], + ['smaxgetredis_81',['smaxGetRedis',['../smax_8c.html#a533fbe770158afe876a3dafa78ba2195',1,'smaxGetRedis(): smax.c'],['../smax_8h.html#a533fbe770158afe876a3dafa78ba2195',1,'smaxGetRedis(): smax.c']]], + ['smaxgetscriptsha1_82',['smaxGetScriptSHA1',['../smax-util_8c.html#a8ef420555c1ddbbcd9f4213f65b4ca66',1,'smaxGetScriptSHA1(const char *scriptName, int *status): smax-util.c'],['../smax_8h.html#a8ef420555c1ddbbcd9f4213f65b4ca66',1,'smaxGetScriptSHA1(const char *scriptName, int *status): smax-util.c']]], + ['smaxgetservertime_83',['smaxGetServerTime',['../smax-util_8c.html#ae6941b762acbd37c60b012d4157681a8',1,'smaxGetServerTime(struct timespec *t): smax-util.c'],['../smax_8h.html#ae6941b762acbd37c60b012d4157681a8',1,'smaxGetServerTime(struct timespec *t): smax-util.c']]], + ['smaxgettime_84',['smaxGetTime',['../smax-util_8c.html#a2a71d93de952060be0154dd5f0d78496',1,'smaxGetTime(const char *timestamp): smax-util.c'],['../smax_8h.html#a2a71d93de952060be0154dd5f0d78496',1,'smaxGetTime(const char *timestamp): smax-util.c']]], + ['smaxgetunits_85',['smaxGetUnits',['../smax-meta_8c.html#aa27e3adeb67f2328a162c80bad433f02',1,'smaxGetUnits(const char *table, const char *key): smax-meta.c'],['../smax_8h.html#aa27e3adeb67f2328a162c80bad433f02',1,'smaxGetUnits(const char *table, const char *key): smax-meta.c']]], + ['smaxisconnected_86',['smaxIsConnected',['../smax_8c.html#a95cbb68e3eb751219ab3363c93a4840b',1,'smaxIsConnected(): smax.c'],['../smax_8h.html#a95cbb68e3eb751219ab3363c93a4840b',1,'smaxIsConnected(): smax.c']]], + ['smaxispipelined_87',['smaxIsPipelined',['../smax_8c.html#af6f57a699b784fc67534cff0abd9573b',1,'smaxIsPipelined(): smax.c'],['../smax_8h.html#af6f57a699b784fc67534cff0abd9573b',1,'smaxIsPipelined(): smax.c']]], + ['smaxisresilient_88',['smaxIsResilient',['../smax-resilient_8c.html#a5f5e00f0fd063ac8e36827c852131358',1,'smaxIsResilient(): smax-resilient.c'],['../smax_8h.html#a5f5e00f0fd063ac8e36827c852131358',1,'smaxIsResilient(): smax-resilient.c']]], + ['smaxisverbose_89',['smaxIsVerbose',['../smax_8c.html#a980232c82ed7ebf5425c60db65f828c0',1,'smaxIsVerbose(): smax.c'],['../smax_8h.html#a980232c82ed7ebf5425c60db65f828c0',1,'smaxIsVerbose(): smax.c']]], + ['smaxkeycount_90',['smaxKeyCount',['../smax_8c.html#a7030106bbe70220c97b1e9e3a4633ff4',1,'smaxKeyCount(const char *table): smax.c'],['../smax_8h.html#a7030106bbe70220c97b1e9e3a4633ff4',1,'smaxKeyCount(const char *table): smax.c']]], + ['smaxlazycache_91',['smaxLazyCache',['../smax-lazy_8c.html#a18027e41c40722011815bc878857e3d0',1,'smaxLazyCache(const char *table, const char *key, XType type): smax-lazy.c'],['../smax_8h.html#a18027e41c40722011815bc878857e3d0',1,'smaxLazyCache(const char *table, const char *key, XType type): smax-lazy.c']]], + ['smaxlazyend_92',['smaxLazyEnd',['../smax-lazy_8c.html#a167a60b494fa9ec5b046f9da796f18b5',1,'smaxLazyEnd(const char *table, const char *key): smax-lazy.c'],['../smax_8h.html#a167a60b494fa9ec5b046f9da796f18b5',1,'smaxLazyEnd(const char *table, const char *key): smax-lazy.c']]], + ['smaxlazyflush_93',['smaxLazyFlush',['../smax-lazy_8c.html#af3d0cff3f8a6ab745907f4544981fdd1',1,'smaxLazyFlush(): smax-lazy.c'],['../smax_8h.html#af3d0cff3f8a6ab745907f4544981fdd1',1,'smaxLazyFlush(): smax-lazy.c']]], + ['smaxlazypull_94',['smaxLazyPull',['../smax-lazy_8c.html#ab50222d7bbaa985fd6d004d67b0269ce',1,'smaxLazyPull(const char *table, const char *key, XType type, int count, void *value, XMeta *meta): smax-lazy.c'],['../smax_8h.html#ab50222d7bbaa985fd6d004d67b0269ce',1,'smaxLazyPull(const char *table, const char *key, XType type, int count, void *value, XMeta *meta): smax-lazy.c']]], + ['smaxlazypullchars_95',['smaxLazyPullChars',['../smax-lazy_8c.html#a45d5c86c16869e5208b9c5cf688adc53',1,'smaxLazyPullChars(const char *table, const char *key, char *buf, int n): smax-lazy.c'],['../smax_8h.html#a45d5c86c16869e5208b9c5cf688adc53',1,'smaxLazyPullChars(const char *table, const char *key, char *buf, int n): smax-lazy.c']]], + ['smaxlazypulldouble_96',['smaxLazyPullDouble',['../smax-lazy_8c.html#a31ed83292a29d69e1c9635b21aae7561',1,'smaxLazyPullDouble(const char *table, const char *key): smax-lazy.c'],['../smax_8h.html#a31ed83292a29d69e1c9635b21aae7561',1,'smaxLazyPullDouble(const char *table, const char *key): smax-lazy.c']]], + ['smaxlazypulldoubledefault_97',['smaxLazyPullDoubleDefault',['../smax-lazy_8c.html#ac823bc3c1ee1bdbc4c330366fc246c8e',1,'smaxLazyPullDoubleDefault(const char *table, const char *key, double defaultValue): smax-lazy.c'],['../smax_8h.html#ac823bc3c1ee1bdbc4c330366fc246c8e',1,'smaxLazyPullDoubleDefault(const char *table, const char *key, double defaultValue): smax-lazy.c']]], + ['smaxlazypulllong_98',['smaxLazyPullLong',['../smax-lazy_8c.html#a03e3bb5c838dc621f8c0ba5fb6fe5f87',1,'smaxLazyPullLong(const char *table, const char *key, long long defaultValue): smax-lazy.c'],['../smax_8h.html#a03e3bb5c838dc621f8c0ba5fb6fe5f87',1,'smaxLazyPullLong(const char *table, const char *key, long long defaultValue): smax-lazy.c']]], + ['smaxlazypullstring_99',['smaxLazyPullString',['../smax-lazy_8c.html#a38d33bcbf9f2f73adbaf040996279859',1,'smaxLazyPullString(const char *table, const char *key): smax-lazy.c'],['../smax_8h.html#a38d33bcbf9f2f73adbaf040996279859',1,'smaxLazyPullString(const char *table, const char *key): smax-lazy.c']]], + ['smaxlazypullstruct_100',['smaxLazyPullStruct',['../smax-lazy_8c.html#af96429709d1b029a8db74cb7407f9ffb',1,'smaxLazyPullStruct(const char *id, XStructure *s): smax-lazy.c'],['../smax_8h.html#af96429709d1b029a8db74cb7407f9ffb',1,'smaxLazyPullStruct(const char *id, XStructure *s): smax-lazy.c']]], + ['smaxparsetime_101',['smaxParseTime',['../smax-util_8c.html#a2c3c82ba5e7844e9f1b70fb4d51716ef',1,'smaxParseTime(const char *timestamp, time_t *secs, long *nanosecs): smax-util.c'],['../smax_8h.html#a2c3c82ba5e7844e9f1b70fb4d51716ef',1,'smaxParseTime(const char *timestamp, time_t *secs, long *nanosecs): smax-util.c']]], + ['smaxpull_102',['smaxPull',['../smax_8c.html#afb7eec789669c3d3f416857d3615ace6',1,'smaxPull(const char *table, const char *key, XType type, int count, void *value, XMeta *meta): smax.c'],['../smax_8h.html#afb7eec789669c3d3f416857d3615ace6',1,'smaxPull(const char *table, const char *key, XType type, int count, void *value, XMeta *meta): smax.c']]], + ['smaxpulldouble_103',['smaxPullDouble',['../smax-easy_8c.html#aa143c2385f210cdd772f014939e1411e',1,'smaxPullDouble(const char *table, const char *key): smax-easy.c'],['../smax_8h.html#aa143c2385f210cdd772f014939e1411e',1,'smaxPullDouble(const char *table, const char *key): smax-easy.c']]], + ['smaxpulldoubledefault_104',['smaxPullDoubleDefault',['../smax-easy_8c.html#a1d30cb3f0a48b567657975a104a1088f',1,'smaxPullDoubleDefault(const char *table, const char *key, double defaultValue): smax-easy.c'],['../smax_8h.html#a1d30cb3f0a48b567657975a104a1088f',1,'smaxPullDoubleDefault(const char *table, const char *key, double defaultValue): smax-easy.c']]], + ['smaxpulldoubles_105',['smaxPullDoubles',['../smax-easy_8c.html#a6e5df36b7eee3944b1ef07edb7f9647d',1,'smaxPullDoubles(const char *table, const char *key, XMeta *meta, int *n): smax-easy.c'],['../smax_8h.html#a6e5df36b7eee3944b1ef07edb7f9647d',1,'smaxPullDoubles(const char *table, const char *key, XMeta *meta, int *n): smax-easy.c']]], + ['smaxpullint_106',['smaxPullInt',['../smax-easy_8c.html#a42685e249ca24359b0f3f2a04a99b16b',1,'smaxPullInt(const char *table, const char *key, int defaultValue): smax-easy.c'],['../smax_8h.html#a42685e249ca24359b0f3f2a04a99b16b',1,'smaxPullInt(const char *table, const char *key, int defaultValue): smax-easy.c']]], + ['smaxpullints_107',['smaxPullInts',['../smax-easy_8c.html#a8cdf0e4d01eaa160b8c96593ce32f4ff',1,'smaxPullInts(const char *table, const char *key, XMeta *meta, int *n): smax-easy.c'],['../smax_8h.html#a8cdf0e4d01eaa160b8c96593ce32f4ff',1,'smaxPullInts(const char *table, const char *key, XMeta *meta, int *n): smax-easy.c']]], + ['smaxpulllong_108',['smaxPullLong',['../smax-easy_8c.html#aebedc01880d4253e74b8bde565de00d5',1,'smaxPullLong(const char *table, const char *key, long long defaultValue): smax-easy.c'],['../smax_8h.html#aebedc01880d4253e74b8bde565de00d5',1,'smaxPullLong(const char *table, const char *key, long long defaultValue): smax-easy.c']]], + ['smaxpulllongs_109',['smaxPullLongs',['../smax-easy_8c.html#a843fa579fa26190335aeebb87be63203',1,'smaxPullLongs(const char *table, const char *key, XMeta *meta, int *n): smax-easy.c'],['../smax_8h.html#a843fa579fa26190335aeebb87be63203',1,'smaxPullLongs(const char *table, const char *key, XMeta *meta, int *n): smax-easy.c']]], + ['smaxpullmeta_110',['smaxPullMeta',['../smax-meta_8c.html#a0d29e7a895c1d5fdc6258ff7426b3521',1,'smaxPullMeta(const char *meta, const char *table, const char *key, int *status): smax-meta.c'],['../smax_8h.html#a0d29e7a895c1d5fdc6258ff7426b3521',1,'smaxPullMeta(const char *meta, const char *table, const char *key, int *status): smax-meta.c']]], + ['smaxpullraw_111',['smaxPullRaw',['../smax-easy_8c.html#a0de71a90fdf235a8aee084543591244f',1,'smaxPullRaw(const char *table, const char *key, XMeta *meta, int *status): smax-easy.c'],['../smax_8h.html#a0de71a90fdf235a8aee084543591244f',1,'smaxPullRaw(const char *table, const char *key, XMeta *meta, int *status): smax-easy.c']]], + ['smaxpullstring_112',['smaxPullString',['../smax-easy_8c.html#a41bdf6bb7bcb3f0d3cb1c0657f8da1c5',1,'smaxPullString(const char *table, const char *key): smax-easy.c'],['../smax_8h.html#a41bdf6bb7bcb3f0d3cb1c0657f8da1c5',1,'smaxPullString(const char *table, const char *key): smax-easy.c']]], + ['smaxpullstrings_113',['smaxPullStrings',['../smax-easy_8c.html#abc833f0d89e672507e0baeb146e8776b',1,'smaxPullStrings(const char *table, const char *key, XMeta *meta, int *n): smax-easy.c'],['../smax_8h.html#abc833f0d89e672507e0baeb146e8776b',1,'smaxPullStrings(const char *table, const char *key, XMeta *meta, int *n): smax-easy.c']]], + ['smaxpullstruct_114',['smaxPullStruct',['../smax-easy_8c.html#a30a2212f19ab2cbf60ea348110475948',1,'smaxPullStruct(const char *id, XMeta *meta, int *status): smax-easy.c'],['../smax_8h.html#ae6d8bf54e6ca203ea25a066d6e439ae5',1,'smaxPullStruct(const char *name, XMeta *meta, int *status): smax-easy.c']]], + ['smaxpulltime_115',['smaxPullTime',['../smax-meta_8c.html#a6deedf594f19417bfa11b8f2cef360c4',1,'smaxPullTime(const char *table, const char *key): smax-meta.c'],['../smax_8h.html#a6deedf594f19417bfa11b8f2cef360c4',1,'smaxPullTime(const char *table, const char *key): smax-meta.c']]], + ['smaxpulltypedimension_116',['smaxPullTypeDimension',['../smax-meta_8c.html#ab989b724600841b16125977bcb44ffcc',1,'smaxPullTypeDimension(const char *table, const char *key, int *ndim, int *sizes): smax-meta.c'],['../smax_8h.html#ab989b724600841b16125977bcb44ffcc',1,'smaxPullTypeDimension(const char *table, const char *key, int *ndim, int *sizes): smax-meta.c']]], + ['smaxpushmeta_117',['smaxPushMeta',['../smax-meta_8c.html#aaf4c866eb1cb30dfd70e04604f1aa6cf',1,'smaxPushMeta(const char *meta, const char *table, const char *key, const char *value): smax-meta.c'],['../smax_8h.html#aaf4c866eb1cb30dfd70e04604f1aa6cf',1,'smaxPushMeta(const char *meta, const char *table, const char *key, const char *value): smax-meta.c']]], + ['smaxqueue_118',['smaxQueue',['../smax-queue_8c.html#a2c71427a215e2253d93de24788db338d',1,'smaxQueue(const char *table, const char *key, XType type, int count, void *value, XMeta *meta): smax-queue.c'],['../smax_8h.html#a2c71427a215e2253d93de24788db338d',1,'smaxQueue(const char *table, const char *key, XType type, int count, void *value, XMeta *meta): smax-queue.c']]], + ['smaxqueuecallback_119',['smaxQueueCallback',['../smax-queue_8c.html#a06781e13ee30b0530ba3ed2e4436b449',1,'smaxQueueCallback(void(*f)(void *), void *arg): smax-queue.c'],['../smax_8h.html#a06781e13ee30b0530ba3ed2e4436b449',1,'smaxQueueCallback(void(*f)(void *), void *arg): smax-queue.c']]], + ['smaxreconnect_120',['smaxReconnect',['../smax_8c.html#aafc75a2e8b8858b8ff0f16e0e73dbd03',1,'smaxReconnect(): smax.c'],['../smax_8h.html#aafc75a2e8b8858b8ff0f16e0e73dbd03',1,'smaxReconnect(): smax.c']]], + ['smaxreleasewaits_121',['smaxReleaseWaits',['../smax_8c.html#a14bc33c30d27be9e2954ae7831099f1c',1,'smaxReleaseWaits(): smax.c'],['../smax_8h.html#a14bc33c30d27be9e2954ae7831099f1c',1,'smaxReleaseWaits(): smax.c']]], + ['smaxremoveconnecthook_122',['smaxRemoveConnectHook',['../smax_8c.html#a4708c3c699781abec237045c48719f3d',1,'smaxRemoveConnectHook(void(*setupCall)(void)): smax.c'],['../smax_8h.html#a4708c3c699781abec237045c48719f3d',1,'smaxRemoveConnectHook(void(*setupCall)(void)): smax.c']]], + ['smaxremovedisconnecthook_123',['smaxRemoveDisconnectHook',['../smax_8c.html#a70cdc3f1bf6b97248b5b8ba6df4dc044',1,'smaxRemoveDisconnectHook(void(*cleanupCall)(void)): smax.c'],['../smax_8h.html#a70cdc3f1bf6b97248b5b8ba6df4dc044',1,'smaxRemoveDisconnectHook(void(*cleanupCall)(void)): smax.c']]], + ['smaxremovemessageprocessor_124',['smaxRemoveMessageProcessor',['../smax-messages_8c.html#a1550f0f7aed841d5576d47ec7e62e0c4',1,'smaxRemoveMessageProcessor(int id): smax-messages.c'],['../smax_8h.html#a1550f0f7aed841d5576d47ec7e62e0c4',1,'smaxRemoveMessageProcessor(int id): smax-messages.c']]], + ['smaxremovesubscribers_125',['smaxRemoveSubscribers',['../smax_8c.html#a77d04f4fbb447f169d40b2a24fa7cf71',1,'smaxRemoveSubscribers(RedisSubscriberCall f): smax.c'],['../smax_8h.html#a77d04f4fbb447f169d40b2a24fa7cf71',1,'smaxRemoveSubscribers(RedisSubscriberCall f): smax.c']]], + ['smaxresetmeta_126',['smaxResetMeta',['../smax-util_8c.html#a7ea3483859bf8f7764143b8590af067e',1,'smaxResetMeta(XMeta *m): smax-util.c'],['../smax_8h.html#a7ea3483859bf8f7764143b8590af067e',1,'smaxResetMeta(XMeta *m): smax-util.c']]], + ['smaxscripterror_127',['smaxScriptError',['../smax-util_8c.html#a3385ed559f3866d76ec4efaa2885daa4',1,'smax-util.c']]], + ['smaxscripterrorasync_128',['smaxScriptErrorAsync',['../smax-util_8c.html#af3acc2100069feec3a52475cdb24d479',1,'smax-util.c']]], + ['smaxsenddebug_129',['smaxSendDebug',['../smax-messages_8c.html#a6c8e73f27c445dedd5ba4ac5b399f8d1',1,'smaxSendDebug(const char *msg): smax-messages.c'],['../smax_8h.html#a6c8e73f27c445dedd5ba4ac5b399f8d1',1,'smaxSendDebug(const char *msg): smax-messages.c']]], + ['smaxsenddetail_130',['smaxSendDetail',['../smax-messages_8c.html#a2a0607da9db140f4227524da37b3bf51',1,'smaxSendDetail(const char *msg): smax-messages.c'],['../smax_8h.html#a2a0607da9db140f4227524da37b3bf51',1,'smaxSendDetail(const char *msg): smax-messages.c']]], + ['smaxsenderror_131',['smaxSendError',['../smax-messages_8c.html#a7d936da43078b9be469a97a6a4bb82a8',1,'smaxSendError(const char *msg): smax-messages.c'],['../smax_8h.html#a7d936da43078b9be469a97a6a4bb82a8',1,'smaxSendError(const char *msg): smax-messages.c']]], + ['smaxsendinfo_132',['smaxSendInfo',['../smax-messages_8c.html#a6056608a81e52d070dcc0f3ee96579b5',1,'smaxSendInfo(const char *msg): smax-messages.c'],['../smax_8h.html#a6056608a81e52d070dcc0f3ee96579b5',1,'smaxSendInfo(const char *msg): smax-messages.c']]], + ['smaxsendprogress_133',['smaxSendProgress',['../smax-messages_8c.html#a0f32699c2148f3b09a48e84b3fa4d036',1,'smaxSendProgress(double fraction, const char *msg): smax-messages.c'],['../smax_8h.html#a0f32699c2148f3b09a48e84b3fa4d036',1,'smaxSendProgress(double fraction, const char *msg): smax-messages.c']]], + ['smaxsendstatus_134',['smaxSendStatus',['../smax-messages_8c.html#a3739383ee6770337b3bb023cfe0cc64c',1,'smaxSendStatus(const char *msg): smax-messages.c'],['../smax_8h.html#a3739383ee6770337b3bb023cfe0cc64c',1,'smaxSendStatus(const char *msg): smax-messages.c']]], + ['smaxsendwarning_135',['smaxSendWarning',['../smax-messages_8c.html#a740f4a171334a6aa5d4736c15fc327e4',1,'smaxSendWarning(const char *msg): smax-messages.c'],['../smax_8h.html#a740f4a171334a6aa5d4736c15fc327e4',1,'smaxSendWarning(const char *msg): smax-messages.c']]], + ['smaxsetauth_136',['smaxSetAuth',['../smax_8c.html#a097b12d3bbb43175084b0b0a2f55339c',1,'smaxSetAuth(const char *username, const char *password): smax.c'],['../smax_8h.html#a097b12d3bbb43175084b0b0a2f55339c',1,'smaxSetAuth(const char *username, const char *password): smax.c']]], + ['smaxsetcoordinateaxis_137',['smaxSetCoordinateAxis',['../smax-meta_8c.html#a5d59620a1646428f41b040d1a0a91554',1,'smaxSetCoordinateAxis(const char *id, int n, const XCoordinateAxis *axis): smax-meta.c'],['../smax_8h.html#a5d59620a1646428f41b040d1a0a91554',1,'smaxSetCoordinateAxis(const char *id, int n, const XCoordinateAxis *axis): smax-meta.c']]], + ['smaxsetcoordinatesystem_138',['smaxSetCoordinateSystem',['../smax-meta_8c.html#a04c3b8ea7ff6b8117d2dba9bf9edd52f',1,'smaxSetCoordinateSystem(const char *table, const char *key, const XCoordinateSystem *coords): smax-meta.c'],['../smax_8h.html#a04c3b8ea7ff6b8117d2dba9bf9edd52f',1,'smaxSetCoordinateSystem(const char *table, const char *key, const XCoordinateSystem *coords): smax-meta.c']]], + ['smaxsetdb_139',['smaxSetDB',['../smax_8c.html#a79fba7411b5afa132457a6828ff5ed9f',1,'smaxSetDB(int idx): smax.c'],['../smax_8h.html#a79fba7411b5afa132457a6828ff5ed9f',1,'smaxSetDB(int idx): smax.c']]], + ['smaxsetdescription_140',['smaxSetDescription',['../smax-meta_8c.html#adcc70ef29ab29f28068ac57e40497b85',1,'smaxSetDescription(const char *table, const char *key, const char *description): smax-meta.c'],['../smax_8h.html#adcc70ef29ab29f28068ac57e40497b85',1,'smaxSetDescription(const char *table, const char *key, const char *description): smax-meta.c']]], + ['smaxsethostname_141',['smaxSetHostName',['../smax_8c.html#a886e2ed23987201a9808f1c99806b44a',1,'smaxSetHostName(const char *name): smax.c'],['../smax_8h.html#a886e2ed23987201a9808f1c99806b44a',1,'smaxSetHostName(const char *name): smax.c']]], + ['smaxsetmaxpendingpulls_142',['smaxSetMaxPendingPulls',['../smax-queue_8c.html#a7b7ff182bf54594d796d52e7d6a1a41d',1,'smaxSetMaxPendingPulls(int n): smax-queue.c'],['../smax_8h.html#a7b7ff182bf54594d796d52e7d6a1a41d',1,'smaxSetMaxPendingPulls(int n): smax-queue.c']]], + ['smaxsetmessagesenderid_143',['smaxSetMessageSenderID',['../smax-messages_8c.html#af3e8295bb941f68cf3177c79cd5fb4d3',1,'smaxSetMessageSenderID(const char *id): smax-messages.c'],['../smax_8h.html#af3e8295bb941f68cf3177c79cd5fb4d3',1,'smaxSetMessageSenderID(const char *id): smax-messages.c']]], + ['smaxsetorigin_144',['smaxSetOrigin',['../smax-util_8c.html#a9802443ba0d569c3614f5dcf8b0cfc4b',1,'smaxSetOrigin(XMeta *m, const char *origin): smax-util.c'],['../smax_8h.html#a9802443ba0d569c3614f5dcf8b0cfc4b',1,'smaxSetOrigin(XMeta *m, const char *origin): smax-util.c']]], + ['smaxsetpipelineconsumer_145',['smaxSetPipelineConsumer',['../smax_8c.html#a542b4c264a49b61a6cd25881290df1d1',1,'smaxSetPipelineConsumer(void(*f)(RESP *)): smax.c'],['../smax_8h.html#a542b4c264a49b61a6cd25881290df1d1',1,'smaxSetPipelineConsumer(void(*f)(RESP *)): smax.c']]], + ['smaxsetpipelined_146',['smaxSetPipelined',['../smax_8c.html#a8d7a3f57360d8e505baa78e445a53875',1,'smaxSetPipelined(boolean isEnabled): smax.c'],['../smax_8h.html#a8d7a3f57360d8e505baa78e445a53875',1,'smaxSetPipelined(boolean isEnabled): smax.c']]], + ['smaxsetresilient_147',['smaxSetResilient',['../smax-resilient_8c.html#a469095a9a74a8ce5d6bbae347d7194e5',1,'smaxSetResilient(boolean value): smax-resilient.c'],['../smax_8h.html#a469095a9a74a8ce5d6bbae347d7194e5',1,'smaxSetResilient(boolean value): smax-resilient.c']]], + ['smaxsetresilientexit_148',['smaxSetResilientExit',['../smax-resilient_8c.html#ae638a5b4c82119eea5ef7a0ba2cd40c1',1,'smaxSetResilientExit(boolean value): smax-resilient.c'],['../smax_8h.html#ae638a5b4c82119eea5ef7a0ba2cd40c1',1,'smaxSetResilientExit(boolean value): smax-resilient.c']]], + ['smaxsetserver_149',['smaxSetServer',['../smax_8c.html#a78cf94f007034f63b609cbe72b8047b0',1,'smaxSetServer(const char *host, int port): smax.c'],['../smax_8h.html#a78cf94f007034f63b609cbe72b8047b0',1,'smaxSetServer(const char *host, int port): smax.c']]], + ['smaxsettcpbuf_150',['smaxSetTcpBuf',['../smax_8c.html#ac42ee8e8128aac0695c68660f04fd196',1,'smaxSetTcpBuf(int size): smax.c'],['../smax_8h.html#ac42ee8e8128aac0695c68660f04fd196',1,'smaxSetTcpBuf(int size): smax.c']]], + ['smaxsetunits_151',['smaxSetUnits',['../smax-meta_8c.html#a23e6627339f6bf58e87150aa9ff0c964',1,'smaxSetUnits(const char *table, const char *key, const char *unit): smax-meta.c'],['../smax_8h.html#a23e6627339f6bf58e87150aa9ff0c964',1,'smaxSetUnits(const char *table, const char *key, const char *unit): smax-meta.c']]], + ['smaxsetverbose_152',['smaxSetVerbose',['../smax_8c.html#ac43709380b9ad92133a22ae0d52d107c',1,'smaxSetVerbose(boolean value): smax.c'],['../smax_8h.html#ac43709380b9ad92133a22ae0d52d107c',1,'smaxSetVerbose(boolean value): smax.c']]], + ['smaxshare_153',['smaxShare',['../smax_8c.html#aee07f085e12283ad96f42c4d77430880',1,'smaxShare(const char *table, const char *key, const void *value, XType type, int count): smax.c'],['../smax_8h.html#aee07f085e12283ad96f42c4d77430880',1,'smaxShare(const char *table, const char *key, const void *value, XType type, int count): smax.c']]], + ['smaxsharearray_154',['smaxShareArray',['../smax_8c.html#a1b116e8ffa85c30991ce6d8afb0319e0',1,'smaxShareArray(const char *table, const char *key, const void *ptr, XType type, int ndim, const int *sizes): smax.c'],['../smax_8h.html#a403f2a3f6186c554cba80ff397ea6a9a',1,'smaxShareArray(const char *table, const char *key, const void *value, XType type, int ndim, const int *sizes): smax.c']]], + ['smaxshareboolean_155',['smaxShareBoolean',['../smax-easy_8c.html#a294640494c2d892dfb4944cd9da7729a',1,'smaxShareBoolean(const char *table, const char *key, boolean value): smax-easy.c'],['../smax_8h.html#a294640494c2d892dfb4944cd9da7729a',1,'smaxShareBoolean(const char *table, const char *key, boolean value): smax-easy.c']]], + ['smaxsharebooleans_156',['smaxShareBooleans',['../smax-easy_8c.html#ad4ddc1226e77667c74dd0c3e0cff56a0',1,'smaxShareBooleans(const char *table, const char *key, const boolean *values, int n): smax-easy.c'],['../smax_8h.html#ad4ddc1226e77667c74dd0c3e0cff56a0',1,'smaxShareBooleans(const char *table, const char *key, const boolean *values, int n): smax-easy.c']]], + ['smaxsharebytes_157',['smaxShareBytes',['../smax-easy_8c.html#a9274e66d69bf41bbe291bbadbb619acc',1,'smaxShareBytes(const char *table, const char *key, const char *values, int n): smax-easy.c'],['../smax_8h.html#a9274e66d69bf41bbe291bbadbb619acc',1,'smaxShareBytes(const char *table, const char *key, const char *values, int n): smax-easy.c']]], + ['smaxsharedouble_158',['smaxShareDouble',['../smax-easy_8c.html#acfbfd2b9a23305d75e45541c5177e42a',1,'smaxShareDouble(const char *table, const char *key, double value): smax-easy.c'],['../smax_8h.html#acfbfd2b9a23305d75e45541c5177e42a',1,'smaxShareDouble(const char *table, const char *key, double value): smax-easy.c']]], + ['smaxsharedoubles_159',['smaxShareDoubles',['../smax-easy_8c.html#a1195017071e3733c0ff9c9f6e704e593',1,'smaxShareDoubles(const char *table, const char *key, const double *values, int n): smax-easy.c'],['../smax_8h.html#a1195017071e3733c0ff9c9f6e704e593',1,'smaxShareDoubles(const char *table, const char *key, const double *values, int n): smax-easy.c']]], + ['smaxsharefield_160',['smaxShareField',['../smax_8c.html#a0da1227278e6bc105c7dbdba14fd884a',1,'smaxShareField(const char *table, const XField *f): smax.c'],['../smax_8h.html#a0da1227278e6bc105c7dbdba14fd884a',1,'smaxShareField(const char *table, const XField *f): smax.c']]], + ['smaxsharefloats_161',['smaxShareFloats',['../smax-easy_8c.html#ace410207bfb5ba9211dc644f7dd2768d',1,'smaxShareFloats(const char *table, const char *key, const float *values, int n): smax-easy.c'],['../smax_8h.html#ace410207bfb5ba9211dc644f7dd2768d',1,'smaxShareFloats(const char *table, const char *key, const float *values, int n): smax-easy.c']]], + ['smaxsharehex_162',['smaxShareHex',['../smax-easy_8c.html#a9efb328571eb7aac0cec75b55676c4e0',1,'smaxShareHex(const char *table, const char *key, long long value): smax-easy.c'],['../smax_8h.html#a9efb328571eb7aac0cec75b55676c4e0',1,'smaxShareHex(const char *table, const char *key, long long value): smax-easy.c']]], + ['smaxshareint_163',['smaxShareInt',['../smax-easy_8c.html#adeb667a3e72acedee7d03eb246b8e1ae',1,'smaxShareInt(const char *table, const char *key, long long value): smax-easy.c'],['../smax_8h.html#adeb667a3e72acedee7d03eb246b8e1ae',1,'smaxShareInt(const char *table, const char *key, long long value): smax-easy.c']]], + ['smaxshareints_164',['smaxShareInts',['../smax-easy_8c.html#acc2181d635e635e330f6e01b7643dadb',1,'smaxShareInts(const char *table, const char *key, const int *values, int n): smax-easy.c'],['../smax_8h.html#acc2181d635e635e330f6e01b7643dadb',1,'smaxShareInts(const char *table, const char *key, const int *values, int n): smax-easy.c']]], + ['smaxsharelongs_165',['smaxShareLongs',['../smax-easy_8c.html#a179730ae8cc7517c96b3e7efb81411fb',1,'smaxShareLongs(const char *table, const char *key, const long long *values, int n): smax-easy.c'],['../smax_8h.html#a179730ae8cc7517c96b3e7efb81411fb',1,'smaxShareLongs(const char *table, const char *key, const long long *values, int n): smax-easy.c']]], + ['smaxshareshorts_166',['smaxShareShorts',['../smax-easy_8c.html#a007815fcac77e840c851a54f97d575ae',1,'smaxShareShorts(const char *table, const char *key, const short *values, int n): smax-easy.c'],['../smax_8h.html#a007815fcac77e840c851a54f97d575ae',1,'smaxShareShorts(const char *table, const char *key, const short *values, int n): smax-easy.c']]], + ['smaxsharestring_167',['smaxShareString',['../smax-easy_8c.html#a5c9657c01a9b8a324a9a1d318dd18e5b',1,'smaxShareString(const char *table, const char *key, const char *sValue): smax-easy.c'],['../smax_8h.html#a5c9657c01a9b8a324a9a1d318dd18e5b',1,'smaxShareString(const char *table, const char *key, const char *sValue): smax-easy.c']]], + ['smaxsharestrings_168',['smaxShareStrings',['../smax-easy_8c.html#a63c421116ca043f2d0899b83d8aa91f9',1,'smaxShareStrings(const char *table, const char *key, const char **sValues, int n): smax-easy.c'],['../smax_8h.html#a63c421116ca043f2d0899b83d8aa91f9',1,'smaxShareStrings(const char *table, const char *key, const char **sValues, int n): smax-easy.c']]], + ['smaxsharestruct_169',['smaxShareStruct',['../smax_8c.html#ab6a1590c953abc1c37fed841cd3a903a',1,'smaxShareStruct(const char *id, const XStructure *s): smax.c'],['../smax_8h.html#ab6a1590c953abc1c37fed841cd3a903a',1,'smaxShareStruct(const char *id, const XStructure *s): smax.c']]], + ['smaxstringtovalues_170',['smaxStringToValues',['../smax-util_8c.html#a9e3c024a1db97e7adc8a40694c657fd1',1,'smaxStringToValues(const char *str, void *value, XType type, int eCount, int *pos): smax-util.c'],['../smax_8h.html#af57aab7c00cf249480b8fda660dc0256',1,'smaxStringToValues(const char *str, void *value, XType type, int count, int *parsed): smax-util.c']]], + ['smaxstringtype_171',['smaxStringType',['../smax-util_8c.html#a8d9d92ad8825d4adad4d6288a5681351',1,'smaxStringType(XType type): smax-util.c'],['../smax_8h.html#a8d9d92ad8825d4adad4d6288a5681351',1,'smaxStringType(XType type): smax-util.c']]], + ['smaxsubscribe_172',['smaxSubscribe',['../smax_8c.html#a53614ba57a594135c13b64a2d89eaa43',1,'smaxSubscribe(const char *table, const char *key): smax.c'],['../smax_8h.html#a53614ba57a594135c13b64a2d89eaa43',1,'smaxSubscribe(const char *table, const char *key): smax.c']]], + ['smaxsync_173',['smaxSync',['../smax-queue_8c.html#a90a901b9e649c77d29379b8fc31cbefc',1,'smaxSync(XSyncPoint *sync, int timeoutMillis): smax-queue.c'],['../smax_8h.html#a90a901b9e649c77d29379b8fc31cbefc',1,'smaxSync(XSyncPoint *sync, int timeoutMillis): smax-queue.c']]], + ['smaxtimestamp_174',['smaxTimestamp',['../smax-util_8c.html#ae56da599747b207813a710efc07dd47d',1,'smaxTimestamp(char *buf): smax-util.c'],['../smax_8h.html#ae56da599747b207813a710efc07dd47d',1,'smaxTimestamp(char *buf): smax-util.c']]], + ['smaxtimetostring_175',['smaxTimeToString',['../smax-util_8c.html#a1c29c7229e7006aea4fc3eb6d4b4ee0e',1,'smaxTimeToString(const struct timespec *time, char *buf): smax-util.c'],['../smax_8h.html#a49ca81e757e023205085a23c3aa7e3da',1,'smaxTimeToString(const struct timespec *time, char *buf): smax-util.c']]], + ['smaxtransmiterrorhandler_176',['smaxTransmitErrorHandler',['../smax-util_8c.html#a164a9c0f870cf0a1fa4f7e66f25452e5',1,'smax-util.c']]], + ['smaxtypeforstring_177',['smaxTypeForString',['../smax-util_8c.html#af6a70e896526629e2130009882a1bff8',1,'smaxTypeForString(const char *type): smax-util.c'],['../smax_8h.html#af6a70e896526629e2130009882a1bff8',1,'smaxTypeForString(const char *type): smax-util.c']]], + ['smaxunpackstrings_178',['smaxUnpackStrings',['../smax-util_8c.html#a5665cd4f5087ab7a07239c30bc561173',1,'smaxUnpackStrings(const char *data, int len, int count, char **dst): smax-util.c'],['../smax_8h.html#a5665cd4f5087ab7a07239c30bc561173',1,'smaxUnpackStrings(const char *data, int len, int count, char **dst): smax-util.c']]], + ['smaxunsubscribe_179',['smaxUnsubscribe',['../smax_8c.html#af3a5d7bc565ab7de0ac1dd8fafc93f14',1,'smaxUnsubscribe(const char *table, const char *key): smax.c'],['../smax_8h.html#af3a5d7bc565ab7de0ac1dd8fafc93f14',1,'smaxUnsubscribe(const char *table, const char *key): smax.c']]], + ['smaxvaluestostring_180',['smaxValuesToString',['../smax-util_8c.html#a4a80ebd309352379d3691f264282d96b',1,'smaxValuesToString(const void *value, XType type, int eCount, char *trybuf, int trylength): smax-util.c'],['../smax_8h.html#ae67f864946fbcd880e7b5c98b2f876c5',1,'smaxValuesToString(const void *value, XType type, int count, char *trybuf, int trylength): smax-util.c']]], + ['smaxwaitonanysubscribed_181',['smaxWaitOnAnySubscribed',['../smax_8c.html#a89db98657eab826392d6099d21fff14c',1,'smaxWaitOnAnySubscribed(char **changedTable, char **changedKey, int timeout): smax.c'],['../smax_8h.html#a89db98657eab826392d6099d21fff14c',1,'smaxWaitOnAnySubscribed(char **changedTable, char **changedKey, int timeout): smax.c']]], + ['smaxwaitonsubscribed_182',['smaxWaitOnSubscribed',['../smax-easy_8c.html#a0e116b41cf8cfbca058dba8476b5d573',1,'smaxWaitOnSubscribed(const char *table, const char *key, int timeout): smax-easy.c'],['../smax_8h.html#a0e116b41cf8cfbca058dba8476b5d573',1,'smaxWaitOnSubscribed(const char *table, const char *key, int timeout): smax-easy.c']]], + ['smaxwaitonsubscribedgroup_183',['smaxWaitOnSubscribedGroup',['../smax-easy_8c.html#af6cae99a805bf84e98390e0bea2470b7',1,'smaxWaitOnSubscribedGroup(const char *matchTable, char **changedKey, int timeout): smax-easy.c'],['../smax_8h.html#af6cae99a805bf84e98390e0bea2470b7',1,'smaxWaitOnSubscribedGroup(const char *matchTable, char **changedKey, int timeout): smax-easy.c']]], + ['smaxwaitonsubscribedvar_184',['smaxWaitOnSubscribedVar',['../smax-easy_8c.html#af54b8b5d2e79eda86b3349c3c138331c',1,'smaxWaitOnSubscribedVar(const char *matchKey, char **changedTable, int timeout): smax-easy.c'],['../smax_8h.html#af54b8b5d2e79eda86b3349c3c138331c',1,'smaxWaitOnSubscribedVar(const char *matchKey, char **changedTable, int timeout): smax-easy.c']]], + ['smaxwaitqueuecomplete_185',['smaxWaitQueueComplete',['../smax-queue_8c.html#a065361085eed93188b7fd3ffe3a7eaf5',1,'smaxWaitQueueComplete(int timeoutMillis): smax-queue.c'],['../smax_8h.html#a065361085eed93188b7fd3ffe3a7eaf5',1,'smaxWaitQueueComplete(int timeoutMillis): smax-queue.c']]], + ['standard_20metadata_186',['Standard metadata',['../index.html#autotoc_md18',1,'']]], + ['status_187',['status',['../structXSyncPoint.html#a6e27f49150e9a14580fb313cc2777e00',1,'XSyncPoint::status'],['../structXMeta.html#a6e27f49150e9a14580fb313cc2777e00',1,'XMeta::status']]], + ['status_20error_20messages_188',['Status / error messages',['../index.html#autotoc_md34',1,'']]], + ['step_189',['step',['../structXCoordinateAxis.html#a4736138d712d9ee570d0652f08a4786a',1,'XCoordinateAxis']]], + ['storebytes_190',['storeBytes',['../structXMeta.html#a766b48fdc93d03992939adfa91766703',1,'XMeta']]], + ['storedim_191',['storeDim',['../structXMeta.html#a16e4b9723516717d3493c46157701520',1,'XMeta']]], + ['storesizes_192',['storeSizes',['../structXMeta.html#adb4556a75a248cce0b72e557c81f8af6',1,'XMeta']]], + ['storetype_193',['storeType',['../structXMeta.html#ace24d22a3441248636253cdb478de9f7',1,'XMeta']]], + ['structures_20substructures_194',['Structures / substructures...',['../index.html#autotoc_md22',1,'']]], + ['substructures_195',['Structures / substructures...',['../index.html#autotoc_md22',1,'']]], + ['support_196',['Debug support',['../index.html#autotoc_md44',1,'']]], + ['synchronization_20points_20and_20waiting_197',['Synchronization points and waiting',['../index.html#autotoc_md27',1,'']]], + ['systems_198',['Systems',['../index.html#autotoc_md38',1,'Coordinate Systems'],['../index.html#autotoc_md40',1,'Coordinate systems']]] +]; diff --git a/apidoc/html/search/all_12.js b/apidoc/html/search/all_12.js new file mode 100644 index 0000000..65eb23e --- /dev/null +++ b/apidoc/html/search/all_12.js @@ -0,0 +1,12 @@ +var searchData= +[ + ['table_20of_20contents_0',['Table of Contents',['../index.html#autotoc_md3',1,'']]], + ['text_1',['text',['../structXMessage.html#a5633b1433389cec21ade3811bbe9ca5b',1,'XMessage']]], + ['the_20basics_2',['The basics',['../index.html#autotoc_md17',1,'']]], + ['the_20sma_20x_20c_20library_3',['Building the SMA-X C library',['../index.html#autotoc_md9',1,'']]], + ['timestamp_4',['timestamp',['../structXMeta.html#a2aace03835c4d951b3dee117b328ef87',1,'XMeta::timestamp'],['../structXMessage.html#a2c17dfa2b3239f2312e94b9de57a7999',1,'XMessage::timestamp']]], + ['to_20disconnecting_20from_20sma_20x_5',['Connecting to / disconnecting from SMA-X',['../index.html#autotoc_md13',1,'']]], + ['to_20redisx_6',['Contributing to RedisX',['../md_CONTRIBUTING.html',1,'']]], + ['type_7',['type',['../structXMessage.html#a23506fc4821ab6d9671f3e6222591a96',1,'XMessage']]], + ['types_20and_20sizes_8',['Flexible types and sizes',['../index.html#autotoc_md19',1,'']]] +]; diff --git a/apidoc/html/search/all_13.js b/apidoc/html/search/all_13.js new file mode 100644 index 0000000..9a3aa16 --- /dev/null +++ b/apidoc/html/search/all_13.js @@ -0,0 +1,9 @@ +var searchData= +[ + ['unit_0',['unit',['../structXCoordinateAxis.html#a5a80171400807274a7fa9c95a104dc78',1,'XCoordinateAxis']]], + ['units_1',['Physical units',['../index.html#autotoc_md39',1,'']]], + ['unreleased_2',['[Unreleased]',['../md_CHANGELOG.html#autotoc_md1',1,'']]], + ['up_3',['Finishing up',['../index.html#autotoc_md29',1,'']]], + ['update_20handling_4',['Custom notifications and update handling',['../index.html#autotoc_md31',1,'']]], + ['updates_5',['Updates',['../index.html#autotoc_md32',1,'Monitoring updates'],['../index.html#autotoc_md33',1,'Waiting for updates']]] +]; diff --git a/apidoc/html/search/all_14.js b/apidoc/html/search/all_14.js new file mode 100644 index 0000000..c2368af --- /dev/null +++ b/apidoc/html/search/all_14.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['volume_20queries_0',['Pipelined pulling (high volume queries)',['../index.html#autotoc_md26',1,'']]] +]; diff --git a/apidoc/html/search/all_15.js b/apidoc/html/search/all_15.js new file mode 100644 index 0000000..0caf29d --- /dev/null +++ b/apidoc/html/search/all_15.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['waiting_0',['Synchronization points and waiting',['../index.html#autotoc_md27',1,'']]], + ['waiting_20for_20updates_1',['Waiting for updates',['../index.html#autotoc_md33',1,'']]] +]; diff --git a/apidoc/html/search/all_16.js b/apidoc/html/search/all_16.js new file mode 100644 index 0000000..15f55f9 --- /dev/null +++ b/apidoc/html/search/all_16.js @@ -0,0 +1,13 @@ +var searchData= +[ + ['x_0',['Connecting to / disconnecting from SMA-X',['../index.html#autotoc_md13',1,'']]], + ['x_20c_20library_1',['Building the SMA-X C library',['../index.html#autotoc_md9',1,'']]], + ['x2smaxfield_2',['x2smaxField',['../smax-util_8c.html#a76bd110891905fe4bdae6628547c50d1',1,'x2smaxField(XField *f): smax-util.c'],['../smax_8h.html#a76bd110891905fe4bdae6628547c50d1',1,'x2smaxField(XField *f): smax-util.c']]], + ['x2smaxstruct_3',['x2smaxStruct',['../smax-util_8c.html#a65cc6cdad09f861b968e2d492abed977',1,'x2smaxStruct(XStructure *s): smax-util.c'],['../smax_8h.html#a65cc6cdad09f861b968e2d492abed977',1,'x2smaxStruct(XStructure *s): smax-util.c']]], + ['x_5fmeta_5finit_4',['X_META_INIT',['../smax_8h.html#a793fead1eb30470e219192befc88b3c9',1,'smax.h']]], + ['xcoordinateaxis_5',['XCoordinateAxis',['../structXCoordinateAxis.html',1,'']]], + ['xcoordinatesystem_6',['XCoordinateSystem',['../structXCoordinateSystem.html',1,'']]], + ['xmessage_7',['XMessage',['../structXMessage.html',1,'']]], + ['xmeta_8',['XMeta',['../structXMeta.html',1,'']]], + ['xsyncpoint_9',['XSyncPoint',['../structXSyncPoint.html',1,'']]] +]; diff --git a/apidoc/html/search/all_2.js b/apidoc/html/search/all_2.js new file mode 100644 index 0000000..b43a951 --- /dev/null +++ b/apidoc/html/search/all_2.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['basics_0',['The basics',['../index.html#autotoc_md17',1,'']]], + ['building_20the_20sma_20x_20c_20library_1',['Building the SMA-X C library',['../index.html#autotoc_md9',1,'']]] +]; diff --git a/apidoc/html/search/all_3.js b/apidoc/html/search/all_3.js new file mode 100644 index 0000000..b089672 --- /dev/null +++ b/apidoc/html/search/all_3.js @@ -0,0 +1,15 @@ +var searchData= +[ + ['c_20library_0',['Building the SMA-X C library',['../index.html#autotoc_md9',1,'']]], + ['callbacks_1',['Callbacks',['../index.html#autotoc_md28',1,'']]], + ['changelog_2',['Changelog',['../md_CHANGELOG.html',1,'']]], + ['clib_3',['smax-clib',['../index.html',1,'']]], + ['configuration_4',['Initial configuration',['../index.html#autotoc_md11',1,'']]], + ['connecting_20to_20disconnecting_20from_20sma_20x_5',['Connecting to / disconnecting from SMA-X',['../index.html#autotoc_md13',1,'']]], + ['connection_20disconnection_20hooks_6',['Connection / disconnection hooks',['../index.html#autotoc_md14',1,'']]], + ['contents_7',['Table of Contents',['../index.html#autotoc_md3',1,'']]], + ['contributing_20to_20redisx_8',['Contributing to RedisX',['../md_CONTRIBUTING.html',1,'']]], + ['coordinate_20systems_9',['Coordinate Systems',['../index.html#autotoc_md38',1,'']]], + ['coordinate_20systems_10',['Coordinate systems',['../index.html#autotoc_md40',1,'']]], + ['custom_20notifications_20and_20update_20handling_11',['Custom notifications and update handling',['../index.html#autotoc_md31',1,'']]] +]; diff --git a/apidoc/html/search/all_4.js b/apidoc/html/search/all_4.js new file mode 100644 index 0000000..968e972 --- /dev/null +++ b/apidoc/html/search/all_4.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['data_0',['Sharing and pulling data',['../index.html#autotoc_md16',1,'']]], + ['debug_20support_1',['Debug support',['../index.html#autotoc_md44',1,'']]], + ['descriptions_2',['Descriptions',['../index.html#autotoc_md37',1,'']]], + ['disconnecting_20from_20sma_20x_3',['Connecting to / disconnecting from SMA-X',['../index.html#autotoc_md13',1,'']]], + ['disconnection_20hooks_4',['Connection / disconnection hooks',['../index.html#autotoc_md14',1,'']]] +]; diff --git a/apidoc/html/search/all_5.js b/apidoc/html/search/all_5.js new file mode 100644 index 0000000..e829b16 --- /dev/null +++ b/apidoc/html/search/all_5.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['error_20handling_0',['Error handling',['../index.html#autotoc_md42',1,'']]], + ['error_20messages_1',['Status / error messages',['../index.html#autotoc_md34',1,'']]] +]; diff --git a/apidoc/html/search/all_6.js b/apidoc/html/search/all_6.js new file mode 100644 index 0000000..eb87ae7 --- /dev/null +++ b/apidoc/html/search/all_6.js @@ -0,0 +1,9 @@ +var searchData= +[ + ['finishing_20up_0',['Finishing up',['../index.html#autotoc_md29',1,'']]], + ['flexible_20types_20and_20sizes_1',['Flexible types and sizes',['../index.html#autotoc_md19',1,'']]], + ['for_20updates_2',['Waiting for updates',['../index.html#autotoc_md33',1,'']]], + ['frequency_20queries_3',['Lazy pulling (high-frequency queries)',['../index.html#autotoc_md24',1,'']]], + ['from_20sma_20x_4',['Connecting to / disconnecting from SMA-X',['../index.html#autotoc_md13',1,'']]], + ['future_20plans_5',['Future plans',['../index.html#autotoc_md46',1,'']]] +]; diff --git a/apidoc/html/search/all_7.js b/apidoc/html/search/all_7.js new file mode 100644 index 0000000..92d5ed0 --- /dev/null +++ b/apidoc/html/search/all_7.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['get_5fstruct_0',['GET_STRUCT',['../smax_8c.html#abc25cf33d9f3d6262a6fe3ffd94a85ae',1,'smax.c']]] +]; diff --git a/apidoc/html/search/all_8.js b/apidoc/html/search/all_8.js new file mode 100644 index 0000000..6885508 --- /dev/null +++ b/apidoc/html/search/all_8.js @@ -0,0 +1,11 @@ +var searchData= +[ + ['handling_0',['Handling',['../index.html#autotoc_md31',1,'Custom notifications and update handling'],['../index.html#autotoc_md42',1,'Error handling']]], + ['hget_5fwith_5fmeta_1',['HGET_WITH_META',['../smax_8c.html#ac5e36a13b5d67f497b15ab44b5a315af',1,'smax.c']]], + ['high_20frequency_20queries_2',['Lazy pulling (high-frequency queries)',['../index.html#autotoc_md24',1,'']]], + ['high_20volume_20queries_3',['Pipelined pulling (high volume queries)',['../index.html#autotoc_md26',1,'']]], + ['hmset_5fwith_5fmeta_4',['HMSET_WITH_META',['../smax_8c.html#a561e3c013e65d6b0703bf1e574d7b821',1,'smax.c']]], + ['hooks_5',['Connection / disconnection hooks',['../index.html#autotoc_md14',1,'']]], + ['host_6',['host',['../structXMessage.html#a1c2046dcb30a629d6d9f45ff8f403f12',1,'XMessage']]], + ['hset_5fwith_5fmeta_7',['HSET_WITH_META',['../smax_8c.html#a6d21bc913aebbf4a95c6c4f6f18da3b4',1,'smax.c']]] +]; diff --git a/apidoc/html/search/all_9.js b/apidoc/html/search/all_9.js new file mode 100644 index 0000000..a0fe9ab --- /dev/null +++ b/apidoc/html/search/all_9.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['initial_20configuration_0',['Initial configuration',['../index.html#autotoc_md11',1,'']]], + ['introduction_1',['Introduction',['../index.html#autotoc_md5',1,'']]], + ['iscomplete_2',['isComplete',['../structXSyncPoint.html#a0b9f91194934aba0d7936d18d4bc81cc',1,'XSyncPoint']]] +]; diff --git a/apidoc/html/search/all_a.js b/apidoc/html/search/all_a.js new file mode 100644 index 0000000..4af33d7 --- /dev/null +++ b/apidoc/html/search/all_a.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['lazy_20pulling_20high_20frequency_20queries_0',['Lazy pulling (high-frequency queries)',['../index.html#autotoc_md24',1,'']]], + ['library_1',['Building the SMA-X C library',['../index.html#autotoc_md9',1,'']]], + ['lock_2',['lock',['../structXSyncPoint.html#a33586b4184d23f2b8f4df153ec23af13',1,'XSyncPoint']]] +]; diff --git a/apidoc/html/search/all_b.js b/apidoc/html/search/all_b.js new file mode 100644 index 0000000..319acc1 --- /dev/null +++ b/apidoc/html/search/all_b.js @@ -0,0 +1,11 @@ +var searchData= +[ + ['messages_0',['Status / error messages',['../index.html#autotoc_md34',1,'']]], + ['messages_5fid_1',['MESSAGES_ID',['../smax-messages_8c.html#a7b2e3f4ba6d955bd23ae56f2a2d9a3e3',1,'smax-messages.c']]], + ['messages_5fprefix_2',['MESSAGES_PREFIX',['../smax-messages_8c.html#a309d33601440402f7f3fb5175864b62b',1,'smax-messages.c']]], + ['meta_5fcoords_3',['META_COORDS',['../smax_8h.html#a6306140d9f65104bc6e0bfd63cbbc2f1',1,'smax.h']]], + ['meta_5fdescription_4',['META_DESCRIPTION',['../smax_8h.html#a3cd80ac3dbca64268a52d6bc8b273d82',1,'smax.h']]], + ['meta_5funit_5',['META_UNIT',['../smax_8h.html#aa1f2f2081a2949053cf74cd4ad47a8d2',1,'smax.h']]], + ['metadata_6',['Metadata',['../index.html#autotoc_md36',1,'Optional metadata'],['../index.html#autotoc_md18',1,'Standard metadata']]], + ['monitoring_20updates_7',['Monitoring updates',['../index.html#autotoc_md32',1,'']]] +]; diff --git a/apidoc/html/search/all_c.js b/apidoc/html/search/all_c.js new file mode 100644 index 0000000..a617491 --- /dev/null +++ b/apidoc/html/search/all_c.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['name_0',['name',['../structXCoordinateAxis.html#a5ac083a645d964373f022d03df4849c8',1,'XCoordinateAxis']]], + ['naxis_1',['nAxis',['../structXCoordinateSystem.html#a66b674e84aa11d53a5f0763237b764ba',1,'XCoordinateSystem']]], + ['notifications_20and_20update_20handling_2',['Custom notifications and update handling',['../index.html#autotoc_md31',1,'']]] +]; diff --git a/apidoc/html/search/all_d.js b/apidoc/html/search/all_d.js new file mode 100644 index 0000000..a3db89c --- /dev/null +++ b/apidoc/html/search/all_d.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['of_20contents_0',['Table of Contents',['../index.html#autotoc_md3',1,'']]], + ['optional_20metadata_1',['Optional metadata',['../index.html#autotoc_md36',1,'']]], + ['origin_2',['origin',['../structXMeta.html#a124de75960ce49e7d4dcbdad9237e128',1,'XMeta']]] +]; diff --git a/apidoc/html/search/all_e.js b/apidoc/html/search/all_e.js new file mode 100644 index 0000000..c8a8db9 --- /dev/null +++ b/apidoc/html/search/all_e.js @@ -0,0 +1,12 @@ +var searchData= +[ + ['physical_20units_0',['Physical units',['../index.html#autotoc_md39',1,'']]], + ['pipelined_20pulling_20high_20volume_20queries_1',['Pipelined pulling (high volume queries)',['../index.html#autotoc_md26',1,'']]], + ['plans_2',['Future plans',['../index.html#autotoc_md46',1,'']]], + ['points_20and_20waiting_3',['Synchronization points and waiting',['../index.html#autotoc_md27',1,'']]], + ['prerequisites_4',['Prerequisites',['../index.html#autotoc_md7',1,'']]], + ['prog_5',['prog',['../structXMessage.html#acc6113e98e7cd24d9dcfa520749a5d3f',1,'XMessage']]], + ['pulling_20data_6',['Sharing and pulling data',['../index.html#autotoc_md16',1,'']]], + ['pulling_20high_20frequency_20queries_7',['Lazy pulling (high-frequency queries)',['../index.html#autotoc_md24',1,'']]], + ['pulling_20high_20volume_20queries_8',['Pipelined pulling (high volume queries)',['../index.html#autotoc_md26',1,'']]] +]; diff --git a/apidoc/html/search/all_f.js b/apidoc/html/search/all_f.js new file mode 100644 index 0000000..e0e0bfa --- /dev/null +++ b/apidoc/html/search/all_f.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['quantities_0',['Scalar quantities',['../index.html#autotoc_md20',1,'']]], + ['queries_1',['Queries',['../index.html#autotoc_md24',1,'Lazy pulling (high-frequency queries)'],['../index.html#autotoc_md26',1,'Pipelined pulling (high volume queries)']]] +]; diff --git a/apidoc/html/search/classes_0.js b/apidoc/html/search/classes_0.js new file mode 100644 index 0000000..f57bf6d --- /dev/null +++ b/apidoc/html/search/classes_0.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['xcoordinateaxis_0',['XCoordinateAxis',['../structXCoordinateAxis.html',1,'']]], + ['xcoordinatesystem_1',['XCoordinateSystem',['../structXCoordinateSystem.html',1,'']]], + ['xmessage_2',['XMessage',['../structXMessage.html',1,'']]], + ['xmeta_3',['XMeta',['../structXMeta.html',1,'']]], + ['xsyncpoint_4',['XSyncPoint',['../structXSyncPoint.html',1,'']]] +]; diff --git a/apidoc/html/search/close.svg b/apidoc/html/search/close.svg new file mode 100644 index 0000000..337d6cc --- /dev/null +++ b/apidoc/html/search/close.svg @@ -0,0 +1,18 @@ + + + + + + diff --git a/apidoc/html/search/defines_0.js b/apidoc/html/search/defines_0.js new file mode 100644 index 0000000..948d04c --- /dev/null +++ b/apidoc/html/search/defines_0.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['_5f_5fxchange_5finternal_5fapi_5f_5f_0',['__XCHANGE_INTERNAL_API__',['../smax-private_8h.html#ac36bd75f87a1614fb477a0fbcd5df1f3',1,'smax-private.h']]] +]; diff --git a/apidoc/html/search/defines_1.js b/apidoc/html/search/defines_1.js new file mode 100644 index 0000000..e5aeb69 --- /dev/null +++ b/apidoc/html/search/defines_1.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['messages_5fid_0',['MESSAGES_ID',['../smax-messages_8c.html#a7b2e3f4ba6d955bd23ae56f2a2d9a3e3',1,'smax-messages.c']]], + ['messages_5fprefix_1',['MESSAGES_PREFIX',['../smax-messages_8c.html#a309d33601440402f7f3fb5175864b62b',1,'smax-messages.c']]], + ['meta_5fcoords_2',['META_COORDS',['../smax_8h.html#a6306140d9f65104bc6e0bfd63cbbc2f1',1,'smax.h']]], + ['meta_5fdescription_3',['META_DESCRIPTION',['../smax_8h.html#a3cd80ac3dbca64268a52d6bc8b273d82',1,'smax.h']]], + ['meta_5funit_4',['META_UNIT',['../smax_8h.html#aa1f2f2081a2949053cf74cd4ad47a8d2',1,'smax.h']]] +]; diff --git a/apidoc/html/search/defines_2.js b/apidoc/html/search/defines_2.js new file mode 100644 index 0000000..17b74a3 --- /dev/null +++ b/apidoc/html/search/defines_2.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['releaseid_0',['RELEASEID',['../smax-private_8h.html#acb5965a4e56d8d90d76002bef3207ef9',1,'smax-private.h']]] +]; diff --git a/apidoc/html/search/defines_3.js b/apidoc/html/search/defines_3.js new file mode 100644 index 0000000..8130d52 --- /dev/null +++ b/apidoc/html/search/defines_3.js @@ -0,0 +1,27 @@ +var searchData= +[ + ['smax_5fdefault_5fhostname_0',['SMAX_DEFAULT_HOSTNAME',['../smax_8h.html#a0fe198db49d87d696072c261e49f7cce',1,'smax.h']]], + ['smax_5fdefault_5fmax_5fqueued_1',['SMAX_DEFAULT_MAX_QUEUED',['../smax_8h.html#aeb7304db99c63c3f0a10fca90e74abe4',1,'smax.h']]], + ['smax_5fdefault_5fpipeline_5fenabled_2',['SMAX_DEFAULT_PIPELINE_ENABLED',['../smax_8h.html#aac2af1cdc522f5e3acc75edf7d41b267',1,'smax.h']]], + ['smax_5fdims_3',['SMAX_DIMS',['../smax_8h.html#a59b5959fb0859d4dbe98408f2cc2f1d0',1,'smax.h']]], + ['smax_5fmsg_5fdebug_4',['SMAX_MSG_DEBUG',['../smax_8h.html#a8b3859624653c39bebe617c91567ad0d',1,'smax.h']]], + ['smax_5fmsg_5fdetail_5',['SMAX_MSG_DETAIL',['../smax_8h.html#a06ee6433a1353c48c2c8ce5e8fd6631c',1,'smax.h']]], + ['smax_5fmsg_5ferror_6',['SMAX_MSG_ERROR',['../smax_8h.html#aeae00b97b43f8563939cd9ebcfdc4c62',1,'smax.h']]], + ['smax_5fmsg_5finfo_7',['SMAX_MSG_INFO',['../smax_8h.html#a539edc8fa4545dbe7c388e8f0644f6c0',1,'smax.h']]], + ['smax_5fmsg_5fprogress_8',['SMAX_MSG_PROGRESS',['../smax_8h.html#a52b656c8731bc8ef9ef83d5307fd157e',1,'smax.h']]], + ['smax_5fmsg_5fstatus_9',['SMAX_MSG_STATUS',['../smax_8h.html#a3168f34d2cd8afae9e9f9848ee684597',1,'smax.h']]], + ['smax_5fmsg_5fwarning_10',['SMAX_MSG_WARNING',['../smax_8h.html#a007762d6503940a6e287efab02083276',1,'smax.h']]], + ['smax_5forigin_5flength_11',['SMAX_ORIGIN_LENGTH',['../smax_8h.html#a012a406ddc842479b2aefaa987e6c591',1,'smax.h']]], + ['smax_5forigins_12',['SMAX_ORIGINS',['../smax_8h.html#a30235420adcb90ff2d2a0f6085a23427',1,'smax.h']]], + ['smax_5fpipe_5fread_5ftimeout_5fmillis_13',['SMAX_PIPE_READ_TIMEOUT_MILLIS',['../smax_8h.html#a38eb97e64eaf65a5273fa6d6ff765a93',1,'smax.h']]], + ['smax_5freads_14',['SMAX_READS',['../smax_8h.html#ab986e2d3951e64cb3300a62c1f010551',1,'smax.h']]], + ['smax_5freconnect_5fretry_5fseconds_15',['SMAX_RECONNECT_RETRY_SECONDS',['../smax_8h.html#a3e9baa458ae59eb26923d6ce863bf700',1,'smax.h']]], + ['smax_5frestore_5fqueue_5fon_5freconnect_16',['SMAX_RESTORE_QUEUE_ON_RECONNECT',['../smax_8h.html#a2f111386ac4b76cd858de99478720b29',1,'smax.h']]], + ['smax_5fscripts_17',['SMAX_SCRIPTS',['../smax_8h.html#a23dedcaf9704eed433cf3920af5e5e1c',1,'smax.h']]], + ['smax_5ftimestamps_18',['SMAX_TIMESTAMPS',['../smax_8h.html#ab5e13a0e5a3b57b087a2c875a01317b4',1,'smax.h']]], + ['smax_5ftypes_19',['SMAX_TYPES',['../smax_8h.html#a6933f3dab1f1de96cca777d65cdd5c40',1,'smax.h']]], + ['smax_5fupdates_20',['SMAX_UPDATES',['../smax_8h.html#a341a9de00cacd431dcd8ac8622b0bf7d',1,'smax.h']]], + ['smax_5fupdates_5flength_21',['SMAX_UPDATES_LENGTH',['../smax_8h.html#ac59ccff9171d5b4e9545fd1ceef027b8',1,'smax.h']]], + ['smax_5fupdates_5froot_22',['SMAX_UPDATES_ROOT',['../smax_8h.html#abfefd74fb72fc51e4577d1fa5fa832f4',1,'smax.h']]], + ['smax_5fwrites_23',['SMAX_WRITES',['../smax_8h.html#af6088c6c91a1f0089000288f0214f67c',1,'smax.h']]] +]; diff --git a/apidoc/html/search/defines_4.js b/apidoc/html/search/defines_4.js new file mode 100644 index 0000000..f088254 --- /dev/null +++ b/apidoc/html/search/defines_4.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['x_5fmeta_5finit_0',['X_META_INIT',['../smax_8h.html#a793fead1eb30470e219192befc88b3c9',1,'smax.h']]] +]; diff --git a/apidoc/html/search/files_0.js b/apidoc/html/search/files_0.js new file mode 100644 index 0000000..54ae5ee --- /dev/null +++ b/apidoc/html/search/files_0.js @@ -0,0 +1,13 @@ +var searchData= +[ + ['smax_2deasy_2ec_0',['smax-easy.c',['../smax-easy_8c.html',1,'']]], + ['smax_2dlazy_2ec_1',['smax-lazy.c',['../smax-lazy_8c.html',1,'']]], + ['smax_2dmessages_2ec_2',['smax-messages.c',['../smax-messages_8c.html',1,'']]], + ['smax_2dmeta_2ec_3',['smax-meta.c',['../smax-meta_8c.html',1,'']]], + ['smax_2dprivate_2eh_4',['smax-private.h',['../smax-private_8h.html',1,'']]], + ['smax_2dqueue_2ec_5',['smax-queue.c',['../smax-queue_8c.html',1,'']]], + ['smax_2dresilient_2ec_6',['smax-resilient.c',['../smax-resilient_8c.html',1,'']]], + ['smax_2dutil_2ec_7',['smax-util.c',['../smax-util_8c.html',1,'']]], + ['smax_2ec_8',['smax.c',['../smax_8c.html',1,'']]], + ['smax_2eh_9',['smax.h',['../smax_8h.html',1,'']]] +]; diff --git a/apidoc/html/search/functions_0.js b/apidoc/html/search/functions_0.js new file mode 100644 index 0000000..e8bc0ca --- /dev/null +++ b/apidoc/html/search/functions_0.js @@ -0,0 +1,148 @@ +var searchData= +[ + ['smax2xfield_0',['smax2xField',['../smax-util_8c.html#abfe751f22aa718133911ffdee848f64a',1,'smax2xField(XField *f): smax-util.c'],['../smax_8h.html#abfe751f22aa718133911ffdee848f64a',1,'smax2xField(XField *f): smax-util.c']]], + ['smax2xstruct_1',['smax2xStruct',['../smax-util_8c.html#a50fef3b0daf40f7de6f52b05abd2963c',1,'smax2xStruct(XStructure *s): smax-util.c'],['../smax_8h.html#a50fef3b0daf40f7de6f52b05abd2963c',1,'smax2xStruct(XStructure *s): smax-util.c']]], + ['smaxaddconnecthook_2',['smaxAddConnectHook',['../smax_8c.html#ad63c425cc3affdf8bc803c7ff8dd6e30',1,'smaxAddConnectHook(void(*setupCall)(void)): smax.c'],['../smax_8h.html#ad63c425cc3affdf8bc803c7ff8dd6e30',1,'smaxAddConnectHook(void(*setupCall)(void)): smax.c']]], + ['smaxadddefaultmessageprocessor_3',['smaxAddDefaultMessageProcessor',['../smax-messages_8c.html#aa3e777f85e81ffb9b02dc8cc3d124a94',1,'smaxAddDefaultMessageProcessor(const char *host, const char *prog, const char *type): smax-messages.c'],['../smax_8h.html#aa3e777f85e81ffb9b02dc8cc3d124a94',1,'smaxAddDefaultMessageProcessor(const char *host, const char *prog, const char *type): smax-messages.c']]], + ['smaxadddisconnecthook_4',['smaxAddDisconnectHook',['../smax_8c.html#a65ae161b28cfe4369709fae1d3ea678c',1,'smaxAddDisconnectHook(void(*cleanupCall)(void)): smax.c'],['../smax_8h.html#a65ae161b28cfe4369709fae1d3ea678c',1,'smaxAddDisconnectHook(void(*cleanupCall)(void)): smax.c']]], + ['smaxaddmessageprocessor_5',['smaxAddMessageProcessor',['../smax-messages_8c.html#abaa2573fb8e85e8359c8853647c38f2f',1,'smaxAddMessageProcessor(const char *host, const char *prog, const char *type, void(*f)(XMessage *)): smax-messages.c'],['../smax_8h.html#abaa2573fb8e85e8359c8853647c38f2f',1,'smaxAddMessageProcessor(const char *host, const char *prog, const char *type, void(*f)(XMessage *)): smax-messages.c']]], + ['smaxaddsubscriber_6',['smaxAddSubscriber',['../smax_8c.html#a827dd87397943f3384605f87116b630c',1,'smaxAddSubscriber(const char *idStem, RedisSubscriberCall f): smax.c'],['../smax_8h.html#a1714cac6dfa55917edecd0028e6da64c',1,'smaxAddSubscriber(const char *stem, RedisSubscriberCall f): smax.c']]], + ['smaxconnect_7',['smaxConnect',['../smax_8c.html#a146fb2ed8512919dc91ecad6d08c74d1',1,'smaxConnect(): smax.c'],['../smax_8h.html#a146fb2ed8512919dc91ecad6d08c74d1',1,'smaxConnect(): smax.c']]], + ['smaxconnectto_8',['smaxConnectTo',['../smax_8c.html#ad960c22b119ff2493a319945a9dd55a5',1,'smaxConnectTo(const char *server): smax.c'],['../smax_8h.html#ad960c22b119ff2493a319945a9dd55a5',1,'smaxConnectTo(const char *server): smax.c']]], + ['smaxcreate1dfield_9',['smaxCreate1DField',['../smax-easy_8c.html#afba357d35d2a1f13d0cf06f5ff708a99',1,'smaxCreate1DField(const char *name, XType type, int size, const void *value): smax-easy.c'],['../smax_8h.html#afba357d35d2a1f13d0cf06f5ff708a99',1,'smaxCreate1DField(const char *name, XType type, int size, const void *value): smax-easy.c']]], + ['smaxcreatebooleanfield_10',['smaxCreateBooleanField',['../smax-easy_8c.html#a13e357c3f20c0799fba6bc6c2a16c520',1,'smaxCreateBooleanField(const char *name, boolean value): smax-easy.c'],['../smax_8h.html#a13e357c3f20c0799fba6bc6c2a16c520',1,'smaxCreateBooleanField(const char *name, boolean value): smax-easy.c']]], + ['smaxcreatecoordinatesystem_11',['smaxCreateCoordinateSystem',['../smax-meta_8c.html#a1d977e7e9eb45f9ce6cc338fdde9bd8f',1,'smaxCreateCoordinateSystem(int nAxis): smax-meta.c'],['../smax_8h.html#a1d977e7e9eb45f9ce6cc338fdde9bd8f',1,'smaxCreateCoordinateSystem(int nAxis): smax-meta.c']]], + ['smaxcreatedoublefield_12',['smaxCreateDoubleField',['../smax-easy_8c.html#afa9c9ec0f47236c0c560eee724b809d6',1,'smaxCreateDoubleField(const char *name, double value): smax-easy.c'],['../smax_8h.html#afa9c9ec0f47236c0c560eee724b809d6',1,'smaxCreateDoubleField(const char *name, double value): smax-easy.c']]], + ['smaxcreatefield_13',['smaxCreateField',['../smax-util_8c.html#a9871356984c4794a9f9caa3870dc6794',1,'smaxCreateField(const char *name, XType type, int ndim, const int *sizes, const void *value): smax-util.c'],['../smax_8h.html#a9871356984c4794a9f9caa3870dc6794',1,'smaxCreateField(const char *name, XType type, int ndim, const int *sizes, const void *value): smax-util.c']]], + ['smaxcreateintfield_14',['smaxCreateIntField',['../smax-easy_8c.html#afcb9ce5f154eef8eccdb0930ec4d613d',1,'smaxCreateIntField(const char *name, int value): smax-easy.c'],['../smax_8h.html#afcb9ce5f154eef8eccdb0930ec4d613d',1,'smaxCreateIntField(const char *name, int value): smax-easy.c']]], + ['smaxcreatelongfield_15',['smaxCreateLongField',['../smax-easy_8c.html#a23b55eae1ce68356073ea5b191f915e5',1,'smaxCreateLongField(const char *name, long long value): smax-easy.c'],['../smax_8h.html#a23b55eae1ce68356073ea5b191f915e5',1,'smaxCreateLongField(const char *name, long long value): smax-easy.c']]], + ['smaxcreatemeta_16',['smaxCreateMeta',['../smax-util_8c.html#a48decaf10195b2f21fa77d8ea9b94fff',1,'smaxCreateMeta(): smax-util.c'],['../smax_8h.html#a48decaf10195b2f21fa77d8ea9b94fff',1,'smaxCreateMeta(): smax-util.c']]], + ['smaxcreatescalarfield_17',['smaxCreateScalarField',['../smax-easy_8c.html#a61a3760159e6867cdb55b5995435633c',1,'smaxCreateScalarField(const char *name, XType type, const void *value): smax-easy.c'],['../smax_8h.html#a61a3760159e6867cdb55b5995435633c',1,'smaxCreateScalarField(const char *name, XType type, const void *value): smax-easy.c']]], + ['smaxcreatestringfield_18',['smaxCreateStringField',['../smax-easy_8c.html#aa5c7661e29f4f1ba62f457c7138f2654',1,'smaxCreateStringField(const char *name, const char *value): smax-easy.c'],['../smax_8h.html#aa5c7661e29f4f1ba62f457c7138f2654',1,'smaxCreateStringField(const char *name, const char *value): smax-easy.c']]], + ['smaxcreatesyncpoint_19',['smaxCreateSyncPoint',['../smax-queue_8c.html#a30e2e1eb462ed2274a55016830b9abc1',1,'smaxCreateSyncPoint(): smax-queue.c'],['../smax_8h.html#a30e2e1eb462ed2274a55016830b9abc1',1,'smaxCreateSyncPoint(): smax-queue.c']]], + ['smaxdeletepattern_20',['smaxDeletePattern',['../smax-util_8c.html#a6c116311d61874554f98332831ad872b',1,'smaxDeletePattern(const char *pattern): smax-util.c'],['../smax_8h.html#a6c116311d61874554f98332831ad872b',1,'smaxDeletePattern(const char *pattern): smax-util.c']]], + ['smaxdestroycoordinatesystem_21',['smaxDestroyCoordinateSystem',['../smax-meta_8c.html#a92cf6cd3b3f123e21a1cee437f87126d',1,'smaxDestroyCoordinateSystem(XCoordinateSystem *coords): smax-meta.c'],['../smax_8h.html#a92cf6cd3b3f123e21a1cee437f87126d',1,'smaxDestroyCoordinateSystem(XCoordinateSystem *coords): smax-meta.c']]], + ['smaxdestroysyncpoint_22',['smaxDestroySyncPoint',['../smax-queue_8c.html#a012860edbebf45f24b1b08c02a37847b',1,'smaxDestroySyncPoint(XSyncPoint *s): smax-queue.c'],['../smax_8h.html#a97ace8424abf924b8ae0397ae83177f2',1,'smaxDestroySyncPoint(XSyncPoint *sync): smax-queue.c']]], + ['smaxdisconnect_23',['smaxDisconnect',['../smax_8c.html#a9d1e6ffa837d3582a8165e326cc44bea',1,'smaxDisconnect(): smax.c'],['../smax_8h.html#a9d1e6ffa837d3582a8165e326cc44bea',1,'smaxDisconnect(): smax.c']]], + ['smaxerror_24',['smaxError',['../smax-util_8c.html#aefcb16af3690ffe9c77224af6b394869',1,'smaxError(const char *func, int errorCode): smax-util.c'],['../smax_8h.html#aefcb16af3690ffe9c77224af6b394869',1,'smaxError(const char *func, int errorCode): smax-util.c']]], + ['smaxerrordescription_25',['smaxErrorDescription',['../smax-util_8c.html#a51856e0dc0261f8e44c8635d31d6193c',1,'smaxErrorDescription(int code): smax-util.c'],['../smax_8h.html#a51856e0dc0261f8e44c8635d31d6193c',1,'smaxErrorDescription(int code): smax-util.c']]], + ['smaxgetarrayfield_26',['smaxGetArrayField',['../smax-easy_8c.html#a10525c664231e85f3cd9a592915b8919',1,'smaxGetArrayField(const XStructure *s, const char *name, void *dst, XType type, int count): smax-easy.c'],['../smax_8h.html#a10525c664231e85f3cd9a592915b8919',1,'smaxGetArrayField(const XStructure *s, const char *name, void *dst, XType type, int count): smax-easy.c']]], + ['smaxgetbooleanfield_27',['smaxGetBooleanField',['../smax-easy_8c.html#a555c133ddd7aee3cf481f9e5e15e3d43',1,'smaxGetBooleanField(const XStructure *s, const char *name, boolean defaultValue): smax-easy.c'],['../smax_8h.html#a555c133ddd7aee3cf481f9e5e15e3d43',1,'smaxGetBooleanField(const XStructure *s, const char *name, boolean defaultValue): smax-easy.c']]], + ['smaxgetcoordinateaxis_28',['smaxGetCoordinateAxis',['../smax-meta_8c.html#a349dc6fe14a2031d679e29804d82d570',1,'smaxGetCoordinateAxis(const char *id, int n): smax-meta.c'],['../smax_8h.html#a349dc6fe14a2031d679e29804d82d570',1,'smaxGetCoordinateAxis(const char *id, int n): smax-meta.c']]], + ['smaxgetcoordinatesystem_29',['smaxGetCoordinateSystem',['../smax-meta_8c.html#a2920bd71f9d340422e0b1b0db4bb3201',1,'smaxGetCoordinateSystem(const char *table, const char *key): smax-meta.c'],['../smax_8h.html#a2920bd71f9d340422e0b1b0db4bb3201',1,'smaxGetCoordinateSystem(const char *table, const char *key): smax-meta.c']]], + ['smaxgetdescription_30',['smaxGetDescription',['../smax-meta_8c.html#ad7ef601ffd5fbcae7b2c05be6f6bc302',1,'smaxGetDescription(const char *table, const char *key): smax-meta.c'],['../smax_8h.html#ad7ef601ffd5fbcae7b2c05be6f6bc302',1,'smaxGetDescription(const char *table, const char *key): smax-meta.c']]], + ['smaxgetdoublefield_31',['smaxGetDoubleField',['../smax-easy_8c.html#ab7c45d4512c22c24153763aa9e227b68',1,'smaxGetDoubleField(const XStructure *s, const char *name, double defaultValue): smax-easy.c'],['../smax_8h.html#ab7c45d4512c22c24153763aa9e227b68',1,'smaxGetDoubleField(const XStructure *s, const char *name, double defaultValue): smax-easy.c']]], + ['smaxgethostname_32',['smaxGetHostName',['../smax_8c.html#ac704fea3e664905af780d2566e3c74b6',1,'smaxGetHostName(): smax.c'],['../smax_8h.html#ac704fea3e664905af780d2566e3c74b6',1,'smaxGetHostName(): smax.c']]], + ['smaxgetkeys_33',['smaxGetKeys',['../smax_8c.html#a2544d1fa602e812004e1d68500024ae0',1,'smaxGetKeys(const char *table, int *n): smax.c'],['../smax_8h.html#a2544d1fa602e812004e1d68500024ae0',1,'smaxGetKeys(const char *table, int *n): smax.c']]], + ['smaxgetlazycached_34',['smaxGetLazyCached',['../smax-lazy_8c.html#a42c08f13c70400dc1225d4097342ded0',1,'smaxGetLazyCached(const char *table, const char *key, XType type, int count, void *value, XMeta *meta): smax-lazy.c'],['../smax_8h.html#a42c08f13c70400dc1225d4097342ded0',1,'smaxGetLazyCached(const char *table, const char *key, XType type, int count, void *value, XMeta *meta): smax-lazy.c']]], + ['smaxgetlazyupdatecount_35',['smaxGetLazyUpdateCount',['../smax-lazy_8c.html#aeca4aa02259278b240e4131f7edea816',1,'smaxGetLazyUpdateCount(const char *table, const char *key): smax-lazy.c'],['../smax_8h.html#aeca4aa02259278b240e4131f7edea816',1,'smaxGetLazyUpdateCount(const char *table, const char *key): smax-lazy.c']]], + ['smaxgetlongfield_36',['smaxGetLongField',['../smax-easy_8c.html#a8035211bd1fe17551a1517560b2547c4',1,'smaxGetLongField(const XStructure *s, const char *name, long long defaultValue): smax-easy.c'],['../smax_8h.html#a8035211bd1fe17551a1517560b2547c4',1,'smaxGetLongField(const XStructure *s, const char *name, long long defaultValue): smax-easy.c']]], + ['smaxgetmetacount_37',['smaxGetMetaCount',['../smax-util_8c.html#ac6d47a508669e4ee215cb72c5366fc52',1,'smaxGetMetaCount(const XMeta *m): smax-util.c'],['../smax_8h.html#ac6d47a508669e4ee215cb72c5366fc52',1,'smaxGetMetaCount(const XMeta *m): smax-util.c']]], + ['smaxgetprogramid_38',['smaxGetProgramID',['../smax_8c.html#abc07a7599e0bac1be15bbcb6b63d4710',1,'smaxGetProgramID(): smax.c'],['../smax_8h.html#abc07a7599e0bac1be15bbcb6b63d4710',1,'smaxGetProgramID(): smax.c']]], + ['smaxgetrawfield_39',['smaxGetRawField',['../smax-easy_8c.html#ada517cdb7737bb38695e2a343123583b',1,'smaxGetRawField(const XStructure *s, const char *name, char *defaultValue): smax-easy.c'],['../smax_8h.html#ada517cdb7737bb38695e2a343123583b',1,'smaxGetRawField(const XStructure *s, const char *name, char *defaultValue): smax-easy.c']]], + ['smaxgetredis_40',['smaxGetRedis',['../smax_8c.html#a533fbe770158afe876a3dafa78ba2195',1,'smaxGetRedis(): smax.c'],['../smax_8h.html#a533fbe770158afe876a3dafa78ba2195',1,'smaxGetRedis(): smax.c']]], + ['smaxgetscriptsha1_41',['smaxGetScriptSHA1',['../smax-util_8c.html#a8ef420555c1ddbbcd9f4213f65b4ca66',1,'smaxGetScriptSHA1(const char *scriptName, int *status): smax-util.c'],['../smax_8h.html#a8ef420555c1ddbbcd9f4213f65b4ca66',1,'smaxGetScriptSHA1(const char *scriptName, int *status): smax-util.c']]], + ['smaxgetservertime_42',['smaxGetServerTime',['../smax-util_8c.html#ae6941b762acbd37c60b012d4157681a8',1,'smaxGetServerTime(struct timespec *t): smax-util.c'],['../smax_8h.html#ae6941b762acbd37c60b012d4157681a8',1,'smaxGetServerTime(struct timespec *t): smax-util.c']]], + ['smaxgettime_43',['smaxGetTime',['../smax-util_8c.html#a2a71d93de952060be0154dd5f0d78496',1,'smaxGetTime(const char *timestamp): smax-util.c'],['../smax_8h.html#a2a71d93de952060be0154dd5f0d78496',1,'smaxGetTime(const char *timestamp): smax-util.c']]], + ['smaxgetunits_44',['smaxGetUnits',['../smax-meta_8c.html#aa27e3adeb67f2328a162c80bad433f02',1,'smaxGetUnits(const char *table, const char *key): smax-meta.c'],['../smax_8h.html#aa27e3adeb67f2328a162c80bad433f02',1,'smaxGetUnits(const char *table, const char *key): smax-meta.c']]], + ['smaxisconnected_45',['smaxIsConnected',['../smax_8c.html#a95cbb68e3eb751219ab3363c93a4840b',1,'smaxIsConnected(): smax.c'],['../smax_8h.html#a95cbb68e3eb751219ab3363c93a4840b',1,'smaxIsConnected(): smax.c']]], + ['smaxispipelined_46',['smaxIsPipelined',['../smax_8c.html#af6f57a699b784fc67534cff0abd9573b',1,'smaxIsPipelined(): smax.c'],['../smax_8h.html#af6f57a699b784fc67534cff0abd9573b',1,'smaxIsPipelined(): smax.c']]], + ['smaxisresilient_47',['smaxIsResilient',['../smax-resilient_8c.html#a5f5e00f0fd063ac8e36827c852131358',1,'smaxIsResilient(): smax-resilient.c'],['../smax_8h.html#a5f5e00f0fd063ac8e36827c852131358',1,'smaxIsResilient(): smax-resilient.c']]], + ['smaxisverbose_48',['smaxIsVerbose',['../smax_8c.html#a980232c82ed7ebf5425c60db65f828c0',1,'smaxIsVerbose(): smax.c'],['../smax_8h.html#a980232c82ed7ebf5425c60db65f828c0',1,'smaxIsVerbose(): smax.c']]], + ['smaxkeycount_49',['smaxKeyCount',['../smax_8c.html#a7030106bbe70220c97b1e9e3a4633ff4',1,'smaxKeyCount(const char *table): smax.c'],['../smax_8h.html#a7030106bbe70220c97b1e9e3a4633ff4',1,'smaxKeyCount(const char *table): smax.c']]], + ['smaxlazycache_50',['smaxLazyCache',['../smax-lazy_8c.html#a18027e41c40722011815bc878857e3d0',1,'smaxLazyCache(const char *table, const char *key, XType type): smax-lazy.c'],['../smax_8h.html#a18027e41c40722011815bc878857e3d0',1,'smaxLazyCache(const char *table, const char *key, XType type): smax-lazy.c']]], + ['smaxlazyend_51',['smaxLazyEnd',['../smax-lazy_8c.html#a167a60b494fa9ec5b046f9da796f18b5',1,'smaxLazyEnd(const char *table, const char *key): smax-lazy.c'],['../smax_8h.html#a167a60b494fa9ec5b046f9da796f18b5',1,'smaxLazyEnd(const char *table, const char *key): smax-lazy.c']]], + ['smaxlazyflush_52',['smaxLazyFlush',['../smax-lazy_8c.html#af3d0cff3f8a6ab745907f4544981fdd1',1,'smaxLazyFlush(): smax-lazy.c'],['../smax_8h.html#af3d0cff3f8a6ab745907f4544981fdd1',1,'smaxLazyFlush(): smax-lazy.c']]], + ['smaxlazypull_53',['smaxLazyPull',['../smax-lazy_8c.html#ab50222d7bbaa985fd6d004d67b0269ce',1,'smaxLazyPull(const char *table, const char *key, XType type, int count, void *value, XMeta *meta): smax-lazy.c'],['../smax_8h.html#ab50222d7bbaa985fd6d004d67b0269ce',1,'smaxLazyPull(const char *table, const char *key, XType type, int count, void *value, XMeta *meta): smax-lazy.c']]], + ['smaxlazypullchars_54',['smaxLazyPullChars',['../smax-lazy_8c.html#a45d5c86c16869e5208b9c5cf688adc53',1,'smaxLazyPullChars(const char *table, const char *key, char *buf, int n): smax-lazy.c'],['../smax_8h.html#a45d5c86c16869e5208b9c5cf688adc53',1,'smaxLazyPullChars(const char *table, const char *key, char *buf, int n): smax-lazy.c']]], + ['smaxlazypulldouble_55',['smaxLazyPullDouble',['../smax-lazy_8c.html#a31ed83292a29d69e1c9635b21aae7561',1,'smaxLazyPullDouble(const char *table, const char *key): smax-lazy.c'],['../smax_8h.html#a31ed83292a29d69e1c9635b21aae7561',1,'smaxLazyPullDouble(const char *table, const char *key): smax-lazy.c']]], + ['smaxlazypulldoubledefault_56',['smaxLazyPullDoubleDefault',['../smax-lazy_8c.html#ac823bc3c1ee1bdbc4c330366fc246c8e',1,'smaxLazyPullDoubleDefault(const char *table, const char *key, double defaultValue): smax-lazy.c'],['../smax_8h.html#ac823bc3c1ee1bdbc4c330366fc246c8e',1,'smaxLazyPullDoubleDefault(const char *table, const char *key, double defaultValue): smax-lazy.c']]], + ['smaxlazypulllong_57',['smaxLazyPullLong',['../smax-lazy_8c.html#a03e3bb5c838dc621f8c0ba5fb6fe5f87',1,'smaxLazyPullLong(const char *table, const char *key, long long defaultValue): smax-lazy.c'],['../smax_8h.html#a03e3bb5c838dc621f8c0ba5fb6fe5f87',1,'smaxLazyPullLong(const char *table, const char *key, long long defaultValue): smax-lazy.c']]], + ['smaxlazypullstring_58',['smaxLazyPullString',['../smax-lazy_8c.html#a38d33bcbf9f2f73adbaf040996279859',1,'smaxLazyPullString(const char *table, const char *key): smax-lazy.c'],['../smax_8h.html#a38d33bcbf9f2f73adbaf040996279859',1,'smaxLazyPullString(const char *table, const char *key): smax-lazy.c']]], + ['smaxlazypullstruct_59',['smaxLazyPullStruct',['../smax-lazy_8c.html#af96429709d1b029a8db74cb7407f9ffb',1,'smaxLazyPullStruct(const char *id, XStructure *s): smax-lazy.c'],['../smax_8h.html#af96429709d1b029a8db74cb7407f9ffb',1,'smaxLazyPullStruct(const char *id, XStructure *s): smax-lazy.c']]], + ['smaxparsetime_60',['smaxParseTime',['../smax-util_8c.html#a2c3c82ba5e7844e9f1b70fb4d51716ef',1,'smaxParseTime(const char *timestamp, time_t *secs, long *nanosecs): smax-util.c'],['../smax_8h.html#a2c3c82ba5e7844e9f1b70fb4d51716ef',1,'smaxParseTime(const char *timestamp, time_t *secs, long *nanosecs): smax-util.c']]], + ['smaxpull_61',['smaxPull',['../smax_8c.html#afb7eec789669c3d3f416857d3615ace6',1,'smaxPull(const char *table, const char *key, XType type, int count, void *value, XMeta *meta): smax.c'],['../smax_8h.html#afb7eec789669c3d3f416857d3615ace6',1,'smaxPull(const char *table, const char *key, XType type, int count, void *value, XMeta *meta): smax.c']]], + ['smaxpulldouble_62',['smaxPullDouble',['../smax-easy_8c.html#aa143c2385f210cdd772f014939e1411e',1,'smaxPullDouble(const char *table, const char *key): smax-easy.c'],['../smax_8h.html#aa143c2385f210cdd772f014939e1411e',1,'smaxPullDouble(const char *table, const char *key): smax-easy.c']]], + ['smaxpulldoubledefault_63',['smaxPullDoubleDefault',['../smax-easy_8c.html#a1d30cb3f0a48b567657975a104a1088f',1,'smaxPullDoubleDefault(const char *table, const char *key, double defaultValue): smax-easy.c'],['../smax_8h.html#a1d30cb3f0a48b567657975a104a1088f',1,'smaxPullDoubleDefault(const char *table, const char *key, double defaultValue): smax-easy.c']]], + ['smaxpulldoubles_64',['smaxPullDoubles',['../smax-easy_8c.html#a6e5df36b7eee3944b1ef07edb7f9647d',1,'smaxPullDoubles(const char *table, const char *key, XMeta *meta, int *n): smax-easy.c'],['../smax_8h.html#a6e5df36b7eee3944b1ef07edb7f9647d',1,'smaxPullDoubles(const char *table, const char *key, XMeta *meta, int *n): smax-easy.c']]], + ['smaxpullint_65',['smaxPullInt',['../smax-easy_8c.html#a42685e249ca24359b0f3f2a04a99b16b',1,'smaxPullInt(const char *table, const char *key, int defaultValue): smax-easy.c'],['../smax_8h.html#a42685e249ca24359b0f3f2a04a99b16b',1,'smaxPullInt(const char *table, const char *key, int defaultValue): smax-easy.c']]], + ['smaxpullints_66',['smaxPullInts',['../smax-easy_8c.html#a8cdf0e4d01eaa160b8c96593ce32f4ff',1,'smaxPullInts(const char *table, const char *key, XMeta *meta, int *n): smax-easy.c'],['../smax_8h.html#a8cdf0e4d01eaa160b8c96593ce32f4ff',1,'smaxPullInts(const char *table, const char *key, XMeta *meta, int *n): smax-easy.c']]], + ['smaxpulllong_67',['smaxPullLong',['../smax-easy_8c.html#aebedc01880d4253e74b8bde565de00d5',1,'smaxPullLong(const char *table, const char *key, long long defaultValue): smax-easy.c'],['../smax_8h.html#aebedc01880d4253e74b8bde565de00d5',1,'smaxPullLong(const char *table, const char *key, long long defaultValue): smax-easy.c']]], + ['smaxpulllongs_68',['smaxPullLongs',['../smax-easy_8c.html#a843fa579fa26190335aeebb87be63203',1,'smaxPullLongs(const char *table, const char *key, XMeta *meta, int *n): smax-easy.c'],['../smax_8h.html#a843fa579fa26190335aeebb87be63203',1,'smaxPullLongs(const char *table, const char *key, XMeta *meta, int *n): smax-easy.c']]], + ['smaxpullmeta_69',['smaxPullMeta',['../smax-meta_8c.html#a0d29e7a895c1d5fdc6258ff7426b3521',1,'smaxPullMeta(const char *meta, const char *table, const char *key, int *status): smax-meta.c'],['../smax_8h.html#a0d29e7a895c1d5fdc6258ff7426b3521',1,'smaxPullMeta(const char *meta, const char *table, const char *key, int *status): smax-meta.c']]], + ['smaxpullraw_70',['smaxPullRaw',['../smax-easy_8c.html#a0de71a90fdf235a8aee084543591244f',1,'smaxPullRaw(const char *table, const char *key, XMeta *meta, int *status): smax-easy.c'],['../smax_8h.html#a0de71a90fdf235a8aee084543591244f',1,'smaxPullRaw(const char *table, const char *key, XMeta *meta, int *status): smax-easy.c']]], + ['smaxpullstring_71',['smaxPullString',['../smax-easy_8c.html#a41bdf6bb7bcb3f0d3cb1c0657f8da1c5',1,'smaxPullString(const char *table, const char *key): smax-easy.c'],['../smax_8h.html#a41bdf6bb7bcb3f0d3cb1c0657f8da1c5',1,'smaxPullString(const char *table, const char *key): smax-easy.c']]], + ['smaxpullstrings_72',['smaxPullStrings',['../smax-easy_8c.html#abc833f0d89e672507e0baeb146e8776b',1,'smaxPullStrings(const char *table, const char *key, XMeta *meta, int *n): smax-easy.c'],['../smax_8h.html#abc833f0d89e672507e0baeb146e8776b',1,'smaxPullStrings(const char *table, const char *key, XMeta *meta, int *n): smax-easy.c']]], + ['smaxpullstruct_73',['smaxPullStruct',['../smax-easy_8c.html#a30a2212f19ab2cbf60ea348110475948',1,'smaxPullStruct(const char *id, XMeta *meta, int *status): smax-easy.c'],['../smax_8h.html#ae6d8bf54e6ca203ea25a066d6e439ae5',1,'smaxPullStruct(const char *name, XMeta *meta, int *status): smax-easy.c']]], + ['smaxpulltime_74',['smaxPullTime',['../smax-meta_8c.html#a6deedf594f19417bfa11b8f2cef360c4',1,'smaxPullTime(const char *table, const char *key): smax-meta.c'],['../smax_8h.html#a6deedf594f19417bfa11b8f2cef360c4',1,'smaxPullTime(const char *table, const char *key): smax-meta.c']]], + ['smaxpulltypedimension_75',['smaxPullTypeDimension',['../smax-meta_8c.html#ab989b724600841b16125977bcb44ffcc',1,'smaxPullTypeDimension(const char *table, const char *key, int *ndim, int *sizes): smax-meta.c'],['../smax_8h.html#ab989b724600841b16125977bcb44ffcc',1,'smaxPullTypeDimension(const char *table, const char *key, int *ndim, int *sizes): smax-meta.c']]], + ['smaxpushmeta_76',['smaxPushMeta',['../smax-meta_8c.html#aaf4c866eb1cb30dfd70e04604f1aa6cf',1,'smaxPushMeta(const char *meta, const char *table, const char *key, const char *value): smax-meta.c'],['../smax_8h.html#aaf4c866eb1cb30dfd70e04604f1aa6cf',1,'smaxPushMeta(const char *meta, const char *table, const char *key, const char *value): smax-meta.c']]], + ['smaxqueue_77',['smaxQueue',['../smax-queue_8c.html#a2c71427a215e2253d93de24788db338d',1,'smaxQueue(const char *table, const char *key, XType type, int count, void *value, XMeta *meta): smax-queue.c'],['../smax_8h.html#a2c71427a215e2253d93de24788db338d',1,'smaxQueue(const char *table, const char *key, XType type, int count, void *value, XMeta *meta): smax-queue.c']]], + ['smaxqueuecallback_78',['smaxQueueCallback',['../smax-queue_8c.html#a06781e13ee30b0530ba3ed2e4436b449',1,'smaxQueueCallback(void(*f)(void *), void *arg): smax-queue.c'],['../smax_8h.html#a06781e13ee30b0530ba3ed2e4436b449',1,'smaxQueueCallback(void(*f)(void *), void *arg): smax-queue.c']]], + ['smaxreconnect_79',['smaxReconnect',['../smax_8c.html#aafc75a2e8b8858b8ff0f16e0e73dbd03',1,'smaxReconnect(): smax.c'],['../smax_8h.html#aafc75a2e8b8858b8ff0f16e0e73dbd03',1,'smaxReconnect(): smax.c']]], + ['smaxreleasewaits_80',['smaxReleaseWaits',['../smax_8c.html#a14bc33c30d27be9e2954ae7831099f1c',1,'smaxReleaseWaits(): smax.c'],['../smax_8h.html#a14bc33c30d27be9e2954ae7831099f1c',1,'smaxReleaseWaits(): smax.c']]], + ['smaxremoveconnecthook_81',['smaxRemoveConnectHook',['../smax_8c.html#a4708c3c699781abec237045c48719f3d',1,'smaxRemoveConnectHook(void(*setupCall)(void)): smax.c'],['../smax_8h.html#a4708c3c699781abec237045c48719f3d',1,'smaxRemoveConnectHook(void(*setupCall)(void)): smax.c']]], + ['smaxremovedisconnecthook_82',['smaxRemoveDisconnectHook',['../smax_8c.html#a70cdc3f1bf6b97248b5b8ba6df4dc044',1,'smaxRemoveDisconnectHook(void(*cleanupCall)(void)): smax.c'],['../smax_8h.html#a70cdc3f1bf6b97248b5b8ba6df4dc044',1,'smaxRemoveDisconnectHook(void(*cleanupCall)(void)): smax.c']]], + ['smaxremovemessageprocessor_83',['smaxRemoveMessageProcessor',['../smax-messages_8c.html#a1550f0f7aed841d5576d47ec7e62e0c4',1,'smaxRemoveMessageProcessor(int id): smax-messages.c'],['../smax_8h.html#a1550f0f7aed841d5576d47ec7e62e0c4',1,'smaxRemoveMessageProcessor(int id): smax-messages.c']]], + ['smaxremovesubscribers_84',['smaxRemoveSubscribers',['../smax_8c.html#a77d04f4fbb447f169d40b2a24fa7cf71',1,'smaxRemoveSubscribers(RedisSubscriberCall f): smax.c'],['../smax_8h.html#a77d04f4fbb447f169d40b2a24fa7cf71',1,'smaxRemoveSubscribers(RedisSubscriberCall f): smax.c']]], + ['smaxresetmeta_85',['smaxResetMeta',['../smax-util_8c.html#a7ea3483859bf8f7764143b8590af067e',1,'smaxResetMeta(XMeta *m): smax-util.c'],['../smax_8h.html#a7ea3483859bf8f7764143b8590af067e',1,'smaxResetMeta(XMeta *m): smax-util.c']]], + ['smaxscripterror_86',['smaxScriptError',['../smax-util_8c.html#a3385ed559f3866d76ec4efaa2885daa4',1,'smax-util.c']]], + ['smaxscripterrorasync_87',['smaxScriptErrorAsync',['../smax-util_8c.html#af3acc2100069feec3a52475cdb24d479',1,'smax-util.c']]], + ['smaxsenddebug_88',['smaxSendDebug',['../smax-messages_8c.html#a6c8e73f27c445dedd5ba4ac5b399f8d1',1,'smaxSendDebug(const char *msg): smax-messages.c'],['../smax_8h.html#a6c8e73f27c445dedd5ba4ac5b399f8d1',1,'smaxSendDebug(const char *msg): smax-messages.c']]], + ['smaxsenddetail_89',['smaxSendDetail',['../smax-messages_8c.html#a2a0607da9db140f4227524da37b3bf51',1,'smaxSendDetail(const char *msg): smax-messages.c'],['../smax_8h.html#a2a0607da9db140f4227524da37b3bf51',1,'smaxSendDetail(const char *msg): smax-messages.c']]], + ['smaxsenderror_90',['smaxSendError',['../smax-messages_8c.html#a7d936da43078b9be469a97a6a4bb82a8',1,'smaxSendError(const char *msg): smax-messages.c'],['../smax_8h.html#a7d936da43078b9be469a97a6a4bb82a8',1,'smaxSendError(const char *msg): smax-messages.c']]], + ['smaxsendinfo_91',['smaxSendInfo',['../smax-messages_8c.html#a6056608a81e52d070dcc0f3ee96579b5',1,'smaxSendInfo(const char *msg): smax-messages.c'],['../smax_8h.html#a6056608a81e52d070dcc0f3ee96579b5',1,'smaxSendInfo(const char *msg): smax-messages.c']]], + ['smaxsendprogress_92',['smaxSendProgress',['../smax-messages_8c.html#a0f32699c2148f3b09a48e84b3fa4d036',1,'smaxSendProgress(double fraction, const char *msg): smax-messages.c'],['../smax_8h.html#a0f32699c2148f3b09a48e84b3fa4d036',1,'smaxSendProgress(double fraction, const char *msg): smax-messages.c']]], + ['smaxsendstatus_93',['smaxSendStatus',['../smax-messages_8c.html#a3739383ee6770337b3bb023cfe0cc64c',1,'smaxSendStatus(const char *msg): smax-messages.c'],['../smax_8h.html#a3739383ee6770337b3bb023cfe0cc64c',1,'smaxSendStatus(const char *msg): smax-messages.c']]], + ['smaxsendwarning_94',['smaxSendWarning',['../smax-messages_8c.html#a740f4a171334a6aa5d4736c15fc327e4',1,'smaxSendWarning(const char *msg): smax-messages.c'],['../smax_8h.html#a740f4a171334a6aa5d4736c15fc327e4',1,'smaxSendWarning(const char *msg): smax-messages.c']]], + ['smaxsetauth_95',['smaxSetAuth',['../smax_8c.html#a097b12d3bbb43175084b0b0a2f55339c',1,'smaxSetAuth(const char *username, const char *password): smax.c'],['../smax_8h.html#a097b12d3bbb43175084b0b0a2f55339c',1,'smaxSetAuth(const char *username, const char *password): smax.c']]], + ['smaxsetcoordinateaxis_96',['smaxSetCoordinateAxis',['../smax-meta_8c.html#a5d59620a1646428f41b040d1a0a91554',1,'smaxSetCoordinateAxis(const char *id, int n, const XCoordinateAxis *axis): smax-meta.c'],['../smax_8h.html#a5d59620a1646428f41b040d1a0a91554',1,'smaxSetCoordinateAxis(const char *id, int n, const XCoordinateAxis *axis): smax-meta.c']]], + ['smaxsetcoordinatesystem_97',['smaxSetCoordinateSystem',['../smax-meta_8c.html#a04c3b8ea7ff6b8117d2dba9bf9edd52f',1,'smaxSetCoordinateSystem(const char *table, const char *key, const XCoordinateSystem *coords): smax-meta.c'],['../smax_8h.html#a04c3b8ea7ff6b8117d2dba9bf9edd52f',1,'smaxSetCoordinateSystem(const char *table, const char *key, const XCoordinateSystem *coords): smax-meta.c']]], + ['smaxsetdb_98',['smaxSetDB',['../smax_8c.html#a79fba7411b5afa132457a6828ff5ed9f',1,'smaxSetDB(int idx): smax.c'],['../smax_8h.html#a79fba7411b5afa132457a6828ff5ed9f',1,'smaxSetDB(int idx): smax.c']]], + ['smaxsetdescription_99',['smaxSetDescription',['../smax-meta_8c.html#adcc70ef29ab29f28068ac57e40497b85',1,'smaxSetDescription(const char *table, const char *key, const char *description): smax-meta.c'],['../smax_8h.html#adcc70ef29ab29f28068ac57e40497b85',1,'smaxSetDescription(const char *table, const char *key, const char *description): smax-meta.c']]], + ['smaxsethostname_100',['smaxSetHostName',['../smax_8c.html#a886e2ed23987201a9808f1c99806b44a',1,'smaxSetHostName(const char *name): smax.c'],['../smax_8h.html#a886e2ed23987201a9808f1c99806b44a',1,'smaxSetHostName(const char *name): smax.c']]], + ['smaxsetmaxpendingpulls_101',['smaxSetMaxPendingPulls',['../smax-queue_8c.html#a7b7ff182bf54594d796d52e7d6a1a41d',1,'smaxSetMaxPendingPulls(int n): smax-queue.c'],['../smax_8h.html#a7b7ff182bf54594d796d52e7d6a1a41d',1,'smaxSetMaxPendingPulls(int n): smax-queue.c']]], + ['smaxsetmessagesenderid_102',['smaxSetMessageSenderID',['../smax-messages_8c.html#af3e8295bb941f68cf3177c79cd5fb4d3',1,'smaxSetMessageSenderID(const char *id): smax-messages.c'],['../smax_8h.html#af3e8295bb941f68cf3177c79cd5fb4d3',1,'smaxSetMessageSenderID(const char *id): smax-messages.c']]], + ['smaxsetorigin_103',['smaxSetOrigin',['../smax-util_8c.html#a9802443ba0d569c3614f5dcf8b0cfc4b',1,'smaxSetOrigin(XMeta *m, const char *origin): smax-util.c'],['../smax_8h.html#a9802443ba0d569c3614f5dcf8b0cfc4b',1,'smaxSetOrigin(XMeta *m, const char *origin): smax-util.c']]], + ['smaxsetpipelineconsumer_104',['smaxSetPipelineConsumer',['../smax_8c.html#a542b4c264a49b61a6cd25881290df1d1',1,'smaxSetPipelineConsumer(void(*f)(RESP *)): smax.c'],['../smax_8h.html#a542b4c264a49b61a6cd25881290df1d1',1,'smaxSetPipelineConsumer(void(*f)(RESP *)): smax.c']]], + ['smaxsetpipelined_105',['smaxSetPipelined',['../smax_8c.html#a8d7a3f57360d8e505baa78e445a53875',1,'smaxSetPipelined(boolean isEnabled): smax.c'],['../smax_8h.html#a8d7a3f57360d8e505baa78e445a53875',1,'smaxSetPipelined(boolean isEnabled): smax.c']]], + ['smaxsetresilient_106',['smaxSetResilient',['../smax-resilient_8c.html#a469095a9a74a8ce5d6bbae347d7194e5',1,'smaxSetResilient(boolean value): smax-resilient.c'],['../smax_8h.html#a469095a9a74a8ce5d6bbae347d7194e5',1,'smaxSetResilient(boolean value): smax-resilient.c']]], + ['smaxsetresilientexit_107',['smaxSetResilientExit',['../smax-resilient_8c.html#ae638a5b4c82119eea5ef7a0ba2cd40c1',1,'smaxSetResilientExit(boolean value): smax-resilient.c'],['../smax_8h.html#ae638a5b4c82119eea5ef7a0ba2cd40c1',1,'smaxSetResilientExit(boolean value): smax-resilient.c']]], + ['smaxsetserver_108',['smaxSetServer',['../smax_8c.html#a78cf94f007034f63b609cbe72b8047b0',1,'smaxSetServer(const char *host, int port): smax.c'],['../smax_8h.html#a78cf94f007034f63b609cbe72b8047b0',1,'smaxSetServer(const char *host, int port): smax.c']]], + ['smaxsettcpbuf_109',['smaxSetTcpBuf',['../smax_8c.html#ac42ee8e8128aac0695c68660f04fd196',1,'smaxSetTcpBuf(int size): smax.c'],['../smax_8h.html#ac42ee8e8128aac0695c68660f04fd196',1,'smaxSetTcpBuf(int size): smax.c']]], + ['smaxsetunits_110',['smaxSetUnits',['../smax-meta_8c.html#a23e6627339f6bf58e87150aa9ff0c964',1,'smaxSetUnits(const char *table, const char *key, const char *unit): smax-meta.c'],['../smax_8h.html#a23e6627339f6bf58e87150aa9ff0c964',1,'smaxSetUnits(const char *table, const char *key, const char *unit): smax-meta.c']]], + ['smaxsetverbose_111',['smaxSetVerbose',['../smax_8c.html#ac43709380b9ad92133a22ae0d52d107c',1,'smaxSetVerbose(boolean value): smax.c'],['../smax_8h.html#ac43709380b9ad92133a22ae0d52d107c',1,'smaxSetVerbose(boolean value): smax.c']]], + ['smaxshare_112',['smaxShare',['../smax_8c.html#aee07f085e12283ad96f42c4d77430880',1,'smaxShare(const char *table, const char *key, const void *value, XType type, int count): smax.c'],['../smax_8h.html#aee07f085e12283ad96f42c4d77430880',1,'smaxShare(const char *table, const char *key, const void *value, XType type, int count): smax.c']]], + ['smaxsharearray_113',['smaxShareArray',['../smax_8c.html#a1b116e8ffa85c30991ce6d8afb0319e0',1,'smaxShareArray(const char *table, const char *key, const void *ptr, XType type, int ndim, const int *sizes): smax.c'],['../smax_8h.html#a403f2a3f6186c554cba80ff397ea6a9a',1,'smaxShareArray(const char *table, const char *key, const void *value, XType type, int ndim, const int *sizes): smax.c']]], + ['smaxshareboolean_114',['smaxShareBoolean',['../smax-easy_8c.html#a294640494c2d892dfb4944cd9da7729a',1,'smaxShareBoolean(const char *table, const char *key, boolean value): smax-easy.c'],['../smax_8h.html#a294640494c2d892dfb4944cd9da7729a',1,'smaxShareBoolean(const char *table, const char *key, boolean value): smax-easy.c']]], + ['smaxsharebooleans_115',['smaxShareBooleans',['../smax-easy_8c.html#ad4ddc1226e77667c74dd0c3e0cff56a0',1,'smaxShareBooleans(const char *table, const char *key, const boolean *values, int n): smax-easy.c'],['../smax_8h.html#ad4ddc1226e77667c74dd0c3e0cff56a0',1,'smaxShareBooleans(const char *table, const char *key, const boolean *values, int n): smax-easy.c']]], + ['smaxsharebytes_116',['smaxShareBytes',['../smax-easy_8c.html#a9274e66d69bf41bbe291bbadbb619acc',1,'smaxShareBytes(const char *table, const char *key, const char *values, int n): smax-easy.c'],['../smax_8h.html#a9274e66d69bf41bbe291bbadbb619acc',1,'smaxShareBytes(const char *table, const char *key, const char *values, int n): smax-easy.c']]], + ['smaxsharedouble_117',['smaxShareDouble',['../smax-easy_8c.html#acfbfd2b9a23305d75e45541c5177e42a',1,'smaxShareDouble(const char *table, const char *key, double value): smax-easy.c'],['../smax_8h.html#acfbfd2b9a23305d75e45541c5177e42a',1,'smaxShareDouble(const char *table, const char *key, double value): smax-easy.c']]], + ['smaxsharedoubles_118',['smaxShareDoubles',['../smax-easy_8c.html#a1195017071e3733c0ff9c9f6e704e593',1,'smaxShareDoubles(const char *table, const char *key, const double *values, int n): smax-easy.c'],['../smax_8h.html#a1195017071e3733c0ff9c9f6e704e593',1,'smaxShareDoubles(const char *table, const char *key, const double *values, int n): smax-easy.c']]], + ['smaxsharefield_119',['smaxShareField',['../smax_8c.html#a0da1227278e6bc105c7dbdba14fd884a',1,'smaxShareField(const char *table, const XField *f): smax.c'],['../smax_8h.html#a0da1227278e6bc105c7dbdba14fd884a',1,'smaxShareField(const char *table, const XField *f): smax.c']]], + ['smaxsharefloats_120',['smaxShareFloats',['../smax-easy_8c.html#ace410207bfb5ba9211dc644f7dd2768d',1,'smaxShareFloats(const char *table, const char *key, const float *values, int n): smax-easy.c'],['../smax_8h.html#ace410207bfb5ba9211dc644f7dd2768d',1,'smaxShareFloats(const char *table, const char *key, const float *values, int n): smax-easy.c']]], + ['smaxsharehex_121',['smaxShareHex',['../smax-easy_8c.html#a9efb328571eb7aac0cec75b55676c4e0',1,'smaxShareHex(const char *table, const char *key, long long value): smax-easy.c'],['../smax_8h.html#a9efb328571eb7aac0cec75b55676c4e0',1,'smaxShareHex(const char *table, const char *key, long long value): smax-easy.c']]], + ['smaxshareint_122',['smaxShareInt',['../smax-easy_8c.html#adeb667a3e72acedee7d03eb246b8e1ae',1,'smaxShareInt(const char *table, const char *key, long long value): smax-easy.c'],['../smax_8h.html#adeb667a3e72acedee7d03eb246b8e1ae',1,'smaxShareInt(const char *table, const char *key, long long value): smax-easy.c']]], + ['smaxshareints_123',['smaxShareInts',['../smax-easy_8c.html#acc2181d635e635e330f6e01b7643dadb',1,'smaxShareInts(const char *table, const char *key, const int *values, int n): smax-easy.c'],['../smax_8h.html#acc2181d635e635e330f6e01b7643dadb',1,'smaxShareInts(const char *table, const char *key, const int *values, int n): smax-easy.c']]], + ['smaxsharelongs_124',['smaxShareLongs',['../smax-easy_8c.html#a179730ae8cc7517c96b3e7efb81411fb',1,'smaxShareLongs(const char *table, const char *key, const long long *values, int n): smax-easy.c'],['../smax_8h.html#a179730ae8cc7517c96b3e7efb81411fb',1,'smaxShareLongs(const char *table, const char *key, const long long *values, int n): smax-easy.c']]], + ['smaxshareshorts_125',['smaxShareShorts',['../smax-easy_8c.html#a007815fcac77e840c851a54f97d575ae',1,'smaxShareShorts(const char *table, const char *key, const short *values, int n): smax-easy.c'],['../smax_8h.html#a007815fcac77e840c851a54f97d575ae',1,'smaxShareShorts(const char *table, const char *key, const short *values, int n): smax-easy.c']]], + ['smaxsharestring_126',['smaxShareString',['../smax-easy_8c.html#a5c9657c01a9b8a324a9a1d318dd18e5b',1,'smaxShareString(const char *table, const char *key, const char *sValue): smax-easy.c'],['../smax_8h.html#a5c9657c01a9b8a324a9a1d318dd18e5b',1,'smaxShareString(const char *table, const char *key, const char *sValue): smax-easy.c']]], + ['smaxsharestrings_127',['smaxShareStrings',['../smax-easy_8c.html#a63c421116ca043f2d0899b83d8aa91f9',1,'smaxShareStrings(const char *table, const char *key, const char **sValues, int n): smax-easy.c'],['../smax_8h.html#a63c421116ca043f2d0899b83d8aa91f9',1,'smaxShareStrings(const char *table, const char *key, const char **sValues, int n): smax-easy.c']]], + ['smaxsharestruct_128',['smaxShareStruct',['../smax_8c.html#ab6a1590c953abc1c37fed841cd3a903a',1,'smaxShareStruct(const char *id, const XStructure *s): smax.c'],['../smax_8h.html#ab6a1590c953abc1c37fed841cd3a903a',1,'smaxShareStruct(const char *id, const XStructure *s): smax.c']]], + ['smaxstringtovalues_129',['smaxStringToValues',['../smax-util_8c.html#a9e3c024a1db97e7adc8a40694c657fd1',1,'smaxStringToValues(const char *str, void *value, XType type, int eCount, int *pos): smax-util.c'],['../smax_8h.html#af57aab7c00cf249480b8fda660dc0256',1,'smaxStringToValues(const char *str, void *value, XType type, int count, int *parsed): smax-util.c']]], + ['smaxstringtype_130',['smaxStringType',['../smax-util_8c.html#a8d9d92ad8825d4adad4d6288a5681351',1,'smaxStringType(XType type): smax-util.c'],['../smax_8h.html#a8d9d92ad8825d4adad4d6288a5681351',1,'smaxStringType(XType type): smax-util.c']]], + ['smaxsubscribe_131',['smaxSubscribe',['../smax_8c.html#a53614ba57a594135c13b64a2d89eaa43',1,'smaxSubscribe(const char *table, const char *key): smax.c'],['../smax_8h.html#a53614ba57a594135c13b64a2d89eaa43',1,'smaxSubscribe(const char *table, const char *key): smax.c']]], + ['smaxsync_132',['smaxSync',['../smax-queue_8c.html#a90a901b9e649c77d29379b8fc31cbefc',1,'smaxSync(XSyncPoint *sync, int timeoutMillis): smax-queue.c'],['../smax_8h.html#a90a901b9e649c77d29379b8fc31cbefc',1,'smaxSync(XSyncPoint *sync, int timeoutMillis): smax-queue.c']]], + ['smaxtimestamp_133',['smaxTimestamp',['../smax-util_8c.html#ae56da599747b207813a710efc07dd47d',1,'smaxTimestamp(char *buf): smax-util.c'],['../smax_8h.html#ae56da599747b207813a710efc07dd47d',1,'smaxTimestamp(char *buf): smax-util.c']]], + ['smaxtimetostring_134',['smaxTimeToString',['../smax-util_8c.html#a1c29c7229e7006aea4fc3eb6d4b4ee0e',1,'smaxTimeToString(const struct timespec *time, char *buf): smax-util.c'],['../smax_8h.html#a49ca81e757e023205085a23c3aa7e3da',1,'smaxTimeToString(const struct timespec *time, char *buf): smax-util.c']]], + ['smaxtransmiterrorhandler_135',['smaxTransmitErrorHandler',['../smax-util_8c.html#a164a9c0f870cf0a1fa4f7e66f25452e5',1,'smax-util.c']]], + ['smaxtypeforstring_136',['smaxTypeForString',['../smax-util_8c.html#af6a70e896526629e2130009882a1bff8',1,'smaxTypeForString(const char *type): smax-util.c'],['../smax_8h.html#af6a70e896526629e2130009882a1bff8',1,'smaxTypeForString(const char *type): smax-util.c']]], + ['smaxunpackstrings_137',['smaxUnpackStrings',['../smax-util_8c.html#a5665cd4f5087ab7a07239c30bc561173',1,'smaxUnpackStrings(const char *data, int len, int count, char **dst): smax-util.c'],['../smax_8h.html#a5665cd4f5087ab7a07239c30bc561173',1,'smaxUnpackStrings(const char *data, int len, int count, char **dst): smax-util.c']]], + ['smaxunsubscribe_138',['smaxUnsubscribe',['../smax_8c.html#af3a5d7bc565ab7de0ac1dd8fafc93f14',1,'smaxUnsubscribe(const char *table, const char *key): smax.c'],['../smax_8h.html#af3a5d7bc565ab7de0ac1dd8fafc93f14',1,'smaxUnsubscribe(const char *table, const char *key): smax.c']]], + ['smaxvaluestostring_139',['smaxValuesToString',['../smax-util_8c.html#a4a80ebd309352379d3691f264282d96b',1,'smaxValuesToString(const void *value, XType type, int eCount, char *trybuf, int trylength): smax-util.c'],['../smax_8h.html#ae67f864946fbcd880e7b5c98b2f876c5',1,'smaxValuesToString(const void *value, XType type, int count, char *trybuf, int trylength): smax-util.c']]], + ['smaxwaitonanysubscribed_140',['smaxWaitOnAnySubscribed',['../smax_8c.html#a89db98657eab826392d6099d21fff14c',1,'smaxWaitOnAnySubscribed(char **changedTable, char **changedKey, int timeout): smax.c'],['../smax_8h.html#a89db98657eab826392d6099d21fff14c',1,'smaxWaitOnAnySubscribed(char **changedTable, char **changedKey, int timeout): smax.c']]], + ['smaxwaitonsubscribed_141',['smaxWaitOnSubscribed',['../smax-easy_8c.html#a0e116b41cf8cfbca058dba8476b5d573',1,'smaxWaitOnSubscribed(const char *table, const char *key, int timeout): smax-easy.c'],['../smax_8h.html#a0e116b41cf8cfbca058dba8476b5d573',1,'smaxWaitOnSubscribed(const char *table, const char *key, int timeout): smax-easy.c']]], + ['smaxwaitonsubscribedgroup_142',['smaxWaitOnSubscribedGroup',['../smax-easy_8c.html#af6cae99a805bf84e98390e0bea2470b7',1,'smaxWaitOnSubscribedGroup(const char *matchTable, char **changedKey, int timeout): smax-easy.c'],['../smax_8h.html#af6cae99a805bf84e98390e0bea2470b7',1,'smaxWaitOnSubscribedGroup(const char *matchTable, char **changedKey, int timeout): smax-easy.c']]], + ['smaxwaitonsubscribedvar_143',['smaxWaitOnSubscribedVar',['../smax-easy_8c.html#af54b8b5d2e79eda86b3349c3c138331c',1,'smaxWaitOnSubscribedVar(const char *matchKey, char **changedTable, int timeout): smax-easy.c'],['../smax_8h.html#af54b8b5d2e79eda86b3349c3c138331c',1,'smaxWaitOnSubscribedVar(const char *matchKey, char **changedTable, int timeout): smax-easy.c']]], + ['smaxwaitqueuecomplete_144',['smaxWaitQueueComplete',['../smax-queue_8c.html#a065361085eed93188b7fd3ffe3a7eaf5',1,'smaxWaitQueueComplete(int timeoutMillis): smax-queue.c'],['../smax_8h.html#a065361085eed93188b7fd3ffe3a7eaf5',1,'smaxWaitQueueComplete(int timeoutMillis): smax-queue.c']]] +]; diff --git a/apidoc/html/search/functions_1.js b/apidoc/html/search/functions_1.js new file mode 100644 index 0000000..6cfd812 --- /dev/null +++ b/apidoc/html/search/functions_1.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['x2smaxfield_0',['x2smaxField',['../smax-util_8c.html#a76bd110891905fe4bdae6628547c50d1',1,'x2smaxField(XField *f): smax-util.c'],['../smax_8h.html#a76bd110891905fe4bdae6628547c50d1',1,'x2smaxField(XField *f): smax-util.c']]], + ['x2smaxstruct_1',['x2smaxStruct',['../smax-util_8c.html#a65cc6cdad09f861b968e2d492abed977',1,'x2smaxStruct(XStructure *s): smax-util.c'],['../smax_8h.html#a65cc6cdad09f861b968e2d492abed977',1,'x2smaxStruct(XStructure *s): smax-util.c']]] +]; diff --git a/apidoc/html/search/mag.svg b/apidoc/html/search/mag.svg new file mode 100644 index 0000000..ffb6cf0 --- /dev/null +++ b/apidoc/html/search/mag.svg @@ -0,0 +1,24 @@ + + + + + + + diff --git a/apidoc/html/search/mag_d.svg b/apidoc/html/search/mag_d.svg new file mode 100644 index 0000000..4122773 --- /dev/null +++ b/apidoc/html/search/mag_d.svg @@ -0,0 +1,24 @@ + + + + + + + diff --git a/apidoc/html/search/mag_sel.svg b/apidoc/html/search/mag_sel.svg new file mode 100644 index 0000000..553dba8 --- /dev/null +++ b/apidoc/html/search/mag_sel.svg @@ -0,0 +1,31 @@ + + + + + + + + + diff --git a/apidoc/html/search/mag_seld.svg b/apidoc/html/search/mag_seld.svg new file mode 100644 index 0000000..c906f84 --- /dev/null +++ b/apidoc/html/search/mag_seld.svg @@ -0,0 +1,31 @@ + + + + + + + + + diff --git a/apidoc/html/search/pages_0.js b/apidoc/html/search/pages_0.js new file mode 100644 index 0000000..4a1de2c --- /dev/null +++ b/apidoc/html/search/pages_0.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['changelog_0',['Changelog',['../md_CHANGELOG.html',1,'']]], + ['clib_1',['smax-clib',['../index.html',1,'']]], + ['contributing_20to_20redisx_2',['Contributing to RedisX',['../md_CONTRIBUTING.html',1,'']]] +]; diff --git a/apidoc/html/search/pages_1.js b/apidoc/html/search/pages_1.js new file mode 100644 index 0000000..81a6980 --- /dev/null +++ b/apidoc/html/search/pages_1.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['redisx_0',['Contributing to RedisX',['../md_CONTRIBUTING.html',1,'']]] +]; diff --git a/apidoc/html/search/pages_2.js b/apidoc/html/search/pages_2.js new file mode 100644 index 0000000..471e7e2 --- /dev/null +++ b/apidoc/html/search/pages_2.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['smax_20clib_0',['smax-clib',['../index.html',1,'']]] +]; diff --git a/apidoc/html/search/pages_3.js b/apidoc/html/search/pages_3.js new file mode 100644 index 0000000..b269349 --- /dev/null +++ b/apidoc/html/search/pages_3.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['to_20redisx_0',['Contributing to RedisX',['../md_CONTRIBUTING.html',1,'']]] +]; diff --git a/apidoc/html/search/search.css b/apidoc/html/search/search.css new file mode 100644 index 0000000..19f76f9 --- /dev/null +++ b/apidoc/html/search/search.css @@ -0,0 +1,291 @@ +/*---------------- Search Box positioning */ + +#main-menu > li:last-child { + /* This
  • object is the parent of the search bar */ + display: flex; + justify-content: center; + align-items: center; + height: 36px; + margin-right: 1em; +} + +/*---------------- Search box styling */ + +.SRPage * { + font-weight: normal; + line-height: normal; +} + +dark-mode-toggle { + margin-left: 5px; + display: flex; + float: right; +} + +#MSearchBox { + display: inline-block; + white-space : nowrap; + background: var(--search-background-color); + border-radius: 0.65em; + box-shadow: var(--search-box-shadow); + z-index: 102; +} + +#MSearchBox .left { + display: inline-block; + vertical-align: middle; + height: 1.4em; +} + +#MSearchSelect { + display: inline-block; + vertical-align: middle; + width: 20px; + height: 19px; + background-image: var(--search-magnification-select-image); + margin: 0 0 0 0.3em; + padding: 0; +} + +#MSearchSelectExt { + display: inline-block; + vertical-align: middle; + width: 10px; + height: 19px; + background-image: var(--search-magnification-image); + margin: 0 0 0 0.5em; + padding: 0; +} + + +#MSearchField { + display: inline-block; + vertical-align: middle; + width: 7.5em; + height: 19px; + margin: 0 0.15em; + padding: 0; + line-height: 1em; + border:none; + color: var(--search-foreground-color); + outline: none; + font-family: var(--font-family-search); + -webkit-border-radius: 0px; + border-radius: 0px; + background: none; +} + +@media(hover: none) { + /* to avoid zooming on iOS */ + #MSearchField { + font-size: 16px; + } +} + +#MSearchBox .right { + display: inline-block; + vertical-align: middle; + width: 1.4em; + height: 1.4em; +} + +#MSearchClose { + display: none; + font-size: inherit; + background : none; + border: none; + margin: 0; + padding: 0; + outline: none; + +} + +#MSearchCloseImg { + padding: 0.3em; + margin: 0; +} + +.MSearchBoxActive #MSearchField { + color: var(--search-active-color); +} + + + +/*---------------- Search filter selection */ + +#MSearchSelectWindow { + display: none; + position: absolute; + left: 0; top: 0; + border: 1px solid var(--search-filter-border-color); + background-color: var(--search-filter-background-color); + z-index: 10001; + padding-top: 4px; + padding-bottom: 4px; + -moz-border-radius: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +.SelectItem { + font: 8pt var(--font-family-search); + padding-left: 2px; + padding-right: 12px; + border: 0px; +} + +span.SelectionMark { + margin-right: 4px; + font-family: var(--font-family-monospace); + outline-style: none; + text-decoration: none; +} + +a.SelectItem { + display: block; + outline-style: none; + color: var(--search-filter-foreground-color); + text-decoration: none; + padding-left: 6px; + padding-right: 12px; +} + +a.SelectItem:focus, +a.SelectItem:active { + color: var(--search-filter-foreground-color); + outline-style: none; + text-decoration: none; +} + +a.SelectItem:hover { + color: var(--search-filter-highlight-text-color); + background-color: var(--search-filter-highlight-bg-color); + outline-style: none; + text-decoration: none; + cursor: pointer; + display: block; +} + +/*---------------- Search results window */ + +iframe#MSearchResults { + /*width: 60ex;*/ + height: 15em; +} + +#MSearchResultsWindow { + display: none; + position: absolute; + left: 0; top: 0; + border: 1px solid var(--search-results-border-color); + background-color: var(--search-results-background-color); + z-index:10000; + width: 300px; + height: 400px; + overflow: auto; +} + +/* ----------------------------------- */ + + +#SRIndex { + clear:both; +} + +.SREntry { + font-size: 10pt; + padding-left: 1ex; +} + +.SRPage .SREntry { + font-size: 8pt; + padding: 1px 5px; +} + +div.SRPage { + margin: 5px 2px; + background-color: var(--search-results-background-color); +} + +.SRChildren { + padding-left: 3ex; padding-bottom: .5em +} + +.SRPage .SRChildren { + display: none; +} + +.SRSymbol { + font-weight: bold; + color: var(--search-results-foreground-color); + font-family: var(--font-family-search); + text-decoration: none; + outline: none; +} + +a.SRScope { + display: block; + color: var(--search-results-foreground-color); + font-family: var(--font-family-search); + font-size: 8pt; + text-decoration: none; + outline: none; +} + +a.SRSymbol:focus, a.SRSymbol:active, +a.SRScope:focus, a.SRScope:active { + text-decoration: underline; +} + +span.SRScope { + padding-left: 4px; + font-family: var(--font-family-search); +} + +.SRPage .SRStatus { + padding: 2px 5px; + font-size: 8pt; + font-style: italic; + font-family: var(--font-family-search); +} + +.SRResult { + display: none; +} + +div.searchresults { + margin-left: 10px; + margin-right: 10px; +} + +/*---------------- External search page results */ + +.pages b { + color: white; + padding: 5px 5px 3px 5px; + background-image: var(--nav-gradient-active-image-parent); + background-repeat: repeat-x; + text-shadow: 0 1px 1px #000000; +} + +.pages { + line-height: 17px; + margin-left: 4px; + text-decoration: none; +} + +.hl { + font-weight: bold; +} + +#searchresults { + margin-bottom: 20px; +} + +.searchpages { + margin-top: 10px; +} + diff --git a/apidoc/html/search/search.js b/apidoc/html/search/search.js new file mode 100644 index 0000000..666af01 --- /dev/null +++ b/apidoc/html/search/search.js @@ -0,0 +1,694 @@ +/* + @licstart The following is the entire license notice for the JavaScript code in this file. + + The MIT License (MIT) + + Copyright (C) 1997-2020 by Dimitri van Heesch + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software + and associated documentation files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, publish, distribute, + sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + @licend The above is the entire license notice for the JavaScript code in this file + */ +const SEARCH_COOKIE_NAME = ''+'search_grp'; + +const searchResults = new SearchResults(); + +/* A class handling everything associated with the search panel. + + Parameters: + name - The name of the global variable that will be + storing this instance. Is needed to be able to set timeouts. + resultPath - path to use for external files +*/ +function SearchBox(name, resultsPath, extension) { + if (!name || !resultsPath) { alert("Missing parameters to SearchBox."); } + if (!extension || extension == "") { extension = ".html"; } + + function getXPos(item) { + let x = 0; + if (item.offsetWidth) { + while (item && item!=document.body) { + x += item.offsetLeft; + item = item.offsetParent; + } + } + return x; + } + + function getYPos(item) { + let y = 0; + if (item.offsetWidth) { + while (item && item!=document.body) { + y += item.offsetTop; + item = item.offsetParent; + } + } + return y; + } + + // ---------- Instance variables + this.name = name; + this.resultsPath = resultsPath; + this.keyTimeout = 0; + this.keyTimeoutLength = 500; + this.closeSelectionTimeout = 300; + this.lastSearchValue = ""; + this.lastResultsPage = ""; + this.hideTimeout = 0; + this.searchIndex = 0; + this.searchActive = false; + this.extension = extension; + + // ----------- DOM Elements + + this.DOMSearchField = () => document.getElementById("MSearchField"); + this.DOMSearchSelect = () => document.getElementById("MSearchSelect"); + this.DOMSearchSelectWindow = () => document.getElementById("MSearchSelectWindow"); + this.DOMPopupSearchResults = () => document.getElementById("MSearchResults"); + this.DOMPopupSearchResultsWindow = () => document.getElementById("MSearchResultsWindow"); + this.DOMSearchClose = () => document.getElementById("MSearchClose"); + this.DOMSearchBox = () => document.getElementById("MSearchBox"); + + // ------------ Event Handlers + + // Called when focus is added or removed from the search field. + this.OnSearchFieldFocus = function(isActive) { + this.Activate(isActive); + } + + this.OnSearchSelectShow = function() { + const searchSelectWindow = this.DOMSearchSelectWindow(); + const searchField = this.DOMSearchSelect(); + + const left = getXPos(searchField); + const top = getYPos(searchField) + searchField.offsetHeight; + + // show search selection popup + searchSelectWindow.style.display='block'; + searchSelectWindow.style.left = left + 'px'; + searchSelectWindow.style.top = top + 'px'; + + // stop selection hide timer + if (this.hideTimeout) { + clearTimeout(this.hideTimeout); + this.hideTimeout=0; + } + return false; // to avoid "image drag" default event + } + + this.OnSearchSelectHide = function() { + this.hideTimeout = setTimeout(this.CloseSelectionWindow.bind(this), + this.closeSelectionTimeout); + } + + // Called when the content of the search field is changed. + this.OnSearchFieldChange = function(evt) { + if (this.keyTimeout) { // kill running timer + clearTimeout(this.keyTimeout); + this.keyTimeout = 0; + } + + const e = evt ? evt : window.event; // for IE + if (e.keyCode==40 || e.keyCode==13) { + if (e.shiftKey==1) { + this.OnSearchSelectShow(); + const win=this.DOMSearchSelectWindow(); + for (let i=0;i do a search + this.Search(); + } + } + + this.OnSearchSelectKey = function(evt) { + const e = (evt) ? evt : window.event; // for IE + if (e.keyCode==40 && this.searchIndex0) { // Up + this.searchIndex--; + this.OnSelectItem(this.searchIndex); + } else if (e.keyCode==13 || e.keyCode==27) { + e.stopPropagation(); + this.OnSelectItem(this.searchIndex); + this.CloseSelectionWindow(); + this.DOMSearchField().focus(); + } + return false; + } + + // --------- Actions + + // Closes the results window. + this.CloseResultsWindow = function() { + this.DOMPopupSearchResultsWindow().style.display = 'none'; + this.DOMSearchClose().style.display = 'none'; + this.Activate(false); + } + + this.CloseSelectionWindow = function() { + this.DOMSearchSelectWindow().style.display = 'none'; + } + + // Performs a search. + this.Search = function() { + this.keyTimeout = 0; + + // strip leading whitespace + const searchValue = this.DOMSearchField().value.replace(/^ +/, ""); + + const code = searchValue.toLowerCase().charCodeAt(0); + let idxChar = searchValue.substr(0, 1).toLowerCase(); + if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1) { // surrogate pair + idxChar = searchValue.substr(0, 2); + } + + let jsFile; + let idx = indexSectionsWithContent[this.searchIndex].indexOf(idxChar); + if (idx!=-1) { + const hexCode=idx.toString(16); + jsFile = this.resultsPath + indexSectionNames[this.searchIndex] + '_' + hexCode + '.js'; + } + + const loadJS = function(url, impl, loc) { + const scriptTag = document.createElement('script'); + scriptTag.src = url; + scriptTag.onload = impl; + scriptTag.onreadystatechange = impl; + loc.appendChild(scriptTag); + } + + const domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow(); + const domSearchBox = this.DOMSearchBox(); + const domPopupSearchResults = this.DOMPopupSearchResults(); + const domSearchClose = this.DOMSearchClose(); + const resultsPath = this.resultsPath; + + const handleResults = function() { + document.getElementById("Loading").style.display="none"; + if (typeof searchData !== 'undefined') { + createResults(resultsPath); + document.getElementById("NoMatches").style.display="none"; + } + + if (idx!=-1) { + searchResults.Search(searchValue); + } else { // no file with search results => force empty search results + searchResults.Search('===='); + } + + if (domPopupSearchResultsWindow.style.display!='block') { + domSearchClose.style.display = 'inline-block'; + let left = getXPos(domSearchBox) + 150; + let top = getYPos(domSearchBox) + 20; + domPopupSearchResultsWindow.style.display = 'block'; + left -= domPopupSearchResults.offsetWidth; + const maxWidth = document.body.clientWidth; + const maxHeight = document.body.clientHeight; + let width = 300; + if (left<10) left=10; + if (width+left+8>maxWidth) width=maxWidth-left-8; + let height = 400; + if (height+top+8>maxHeight) height=maxHeight-top-8; + domPopupSearchResultsWindow.style.top = top + 'px'; + domPopupSearchResultsWindow.style.left = left + 'px'; + domPopupSearchResultsWindow.style.width = width + 'px'; + domPopupSearchResultsWindow.style.height = height + 'px'; + } + } + + if (jsFile) { + loadJS(jsFile, handleResults, this.DOMPopupSearchResultsWindow()); + } else { + handleResults(); + } + + this.lastSearchValue = searchValue; + } + + // -------- Activation Functions + + // Activates or deactivates the search panel, resetting things to + // their default values if necessary. + this.Activate = function(isActive) { + if (isActive || // open it + this.DOMPopupSearchResultsWindow().style.display == 'block' + ) { + this.DOMSearchBox().className = 'MSearchBoxActive'; + this.searchActive = true; + } else if (!isActive) { // directly remove the panel + this.DOMSearchBox().className = 'MSearchBoxInactive'; + this.searchActive = false; + this.lastSearchValue = '' + this.lastResultsPage = ''; + this.DOMSearchField().value = ''; + } + } +} + +// ----------------------------------------------------------------------- + +// The class that handles everything on the search results page. +function SearchResults() { + + function convertToId(search) { + let result = ''; + for (let i=0;i. + this.lastMatchCount = 0; + this.lastKey = 0; + this.repeatOn = false; + + // Toggles the visibility of the passed element ID. + this.FindChildElement = function(id) { + const parentElement = document.getElementById(id); + let element = parentElement.firstChild; + + while (element && element!=parentElement) { + if (element.nodeName.toLowerCase() == 'div' && element.className == 'SRChildren') { + return element; + } + + if (element.nodeName.toLowerCase() == 'div' && element.hasChildNodes()) { + element = element.firstChild; + } else if (element.nextSibling) { + element = element.nextSibling; + } else { + do { + element = element.parentNode; + } + while (element && element!=parentElement && !element.nextSibling); + + if (element && element!=parentElement) { + element = element.nextSibling; + } + } + } + } + + this.Toggle = function(id) { + const element = this.FindChildElement(id); + if (element) { + if (element.style.display == 'block') { + element.style.display = 'none'; + } else { + element.style.display = 'block'; + } + } + } + + // Searches for the passed string. If there is no parameter, + // it takes it from the URL query. + // + // Always returns true, since other documents may try to call it + // and that may or may not be possible. + this.Search = function(search) { + if (!search) { // get search word from URL + search = window.location.search; + search = search.substring(1); // Remove the leading '?' + search = unescape(search); + } + + search = search.replace(/^ +/, ""); // strip leading spaces + search = search.replace(/ +$/, ""); // strip trailing spaces + search = search.toLowerCase(); + search = convertToId(search); + + const resultRows = document.getElementsByTagName("div"); + let matches = 0; + + let i = 0; + while (i < resultRows.length) { + const row = resultRows.item(i); + if (row.className == "SRResult") { + let rowMatchName = row.id.toLowerCase(); + rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); // strip 'sr123_' + + if (search.length<=rowMatchName.length && + rowMatchName.substr(0, search.length)==search) { + row.style.display = 'block'; + matches++; + } else { + row.style.display = 'none'; + } + } + i++; + } + document.getElementById("Searching").style.display='none'; + if (matches == 0) { // no results + document.getElementById("NoMatches").style.display='block'; + } else { // at least one result + document.getElementById("NoMatches").style.display='none'; + } + this.lastMatchCount = matches; + return true; + } + + // return the first item with index index or higher that is visible + this.NavNext = function(index) { + let focusItem; + for (;;) { + const focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') { + break; + } else if (!focusItem) { // last element + break; + } + focusItem=null; + index++; + } + return focusItem; + } + + this.NavPrev = function(index) { + let focusItem; + for (;;) { + const focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') { + break; + } else if (!focusItem) { // last element + break; + } + focusItem=null; + index--; + } + return focusItem; + } + + this.ProcessKeys = function(e) { + if (e.type == "keydown") { + this.repeatOn = false; + this.lastKey = e.keyCode; + } else if (e.type == "keypress") { + if (!this.repeatOn) { + if (this.lastKey) this.repeatOn = true; + return false; // ignore first keypress after keydown + } + } else if (e.type == "keyup") { + this.lastKey = 0; + this.repeatOn = false; + } + return this.lastKey!=0; + } + + this.Nav = function(evt,itemIndex) { + const e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) { // Up + const newIndex = itemIndex-1; + let focusItem = this.NavPrev(newIndex); + if (focusItem) { + let child = this.FindChildElement(focusItem.parentNode.parentNode.id); + if (child && child.style.display == 'block') { // children visible + let n=0; + let tmpElem; + for (;;) { // search for last child + tmpElem = document.getElementById('Item'+newIndex+'_c'+n); + if (tmpElem) { + focusItem = tmpElem; + } else { // found it! + break; + } + n++; + } + } + } + if (focusItem) { + focusItem.focus(); + } else { // return focus to search field + document.getElementById("MSearchField").focus(); + } + } else if (this.lastKey==40) { // Down + const newIndex = itemIndex+1; + let focusItem; + const item = document.getElementById('Item'+itemIndex); + const elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem && elem.style.display == 'block') { // children visible + focusItem = document.getElementById('Item'+itemIndex+'_c0'); + } + if (!focusItem) focusItem = this.NavNext(newIndex); + if (focusItem) focusItem.focus(); + } else if (this.lastKey==39) { // Right + const item = document.getElementById('Item'+itemIndex); + const elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'block'; + } else if (this.lastKey==37) { // Left + const item = document.getElementById('Item'+itemIndex); + const elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'none'; + } else if (this.lastKey==27) { // Escape + e.stopPropagation(); + searchBox.CloseResultsWindow(); + document.getElementById("MSearchField").focus(); + } else if (this.lastKey==13) { // Enter + return true; + } + return false; + } + + this.NavChild = function(evt,itemIndex,childIndex) { + const e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) { // Up + if (childIndex>0) { + const newIndex = childIndex-1; + document.getElementById('Item'+itemIndex+'_c'+newIndex).focus(); + } else { // already at first child, jump to parent + document.getElementById('Item'+itemIndex).focus(); + } + } else if (this.lastKey==40) { // Down + const newIndex = childIndex+1; + let elem = document.getElementById('Item'+itemIndex+'_c'+newIndex); + if (!elem) { // last child, jump to parent next parent + elem = this.NavNext(itemIndex+1); + } + if (elem) { + elem.focus(); + } + } else if (this.lastKey==27) { // Escape + e.stopPropagation(); + searchBox.CloseResultsWindow(); + document.getElementById("MSearchField").focus(); + } else if (this.lastKey==13) { // Enter + return true; + } + return false; + } +} + +function createResults(resultsPath) { + + function setKeyActions(elem,action) { + elem.setAttribute('onkeydown',action); + elem.setAttribute('onkeypress',action); + elem.setAttribute('onkeyup',action); + } + + function setClassAttr(elem,attr) { + elem.setAttribute('class',attr); + elem.setAttribute('className',attr); + } + + const results = document.getElementById("SRResults"); + results.innerHTML = ''; + searchData.forEach((elem,index) => { + const id = elem[0]; + const srResult = document.createElement('div'); + srResult.setAttribute('id','SR_'+id); + setClassAttr(srResult,'SRResult'); + const srEntry = document.createElement('div'); + setClassAttr(srEntry,'SREntry'); + const srLink = document.createElement('a'); + srLink.setAttribute('id','Item'+index); + setKeyActions(srLink,'return searchResults.Nav(event,'+index+')'); + setClassAttr(srLink,'SRSymbol'); + srLink.innerHTML = elem[1][0]; + srEntry.appendChild(srLink); + if (elem[1].length==2) { // single result + srLink.setAttribute('href',resultsPath+elem[1][1][0]); + srLink.setAttribute('onclick','searchBox.CloseResultsWindow()'); + if (elem[1][1][1]) { + srLink.setAttribute('target','_parent'); + } else { + srLink.setAttribute('target','_blank'); + } + const srScope = document.createElement('span'); + setClassAttr(srScope,'SRScope'); + srScope.innerHTML = elem[1][1][2]; + srEntry.appendChild(srScope); + } else { // multiple results + srLink.setAttribute('href','javascript:searchResults.Toggle("SR_'+id+'")'); + const srChildren = document.createElement('div'); + setClassAttr(srChildren,'SRChildren'); + for (let c=0; c + + + + + + +smax-clib: src/smax-easy.c File Reference + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + +
    +
    smax-clib v0.9 +
    +
    A C/C++ client library for SMA-X
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    + +
    smax-easy.c File Reference
    +
    +
    + +

    A set of functions for simplified access to SMA-X for specific variable types. +More...

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    +Functions

    XField * smaxCreate1DField (const char *name, XType type, int size, const void *value)
     
    XField * smaxCreateBooleanField (const char *name, boolean value)
     
    XField * smaxCreateDoubleField (const char *name, double value)
     
    XField * smaxCreateIntField (const char *name, int value)
     
    XField * smaxCreateLongField (const char *name, long long value)
     
    XField * smaxCreateScalarField (const char *name, XType type, const void *value)
     
    XField * smaxCreateStringField (const char *name, const char *value)
     
    int smaxGetArrayField (const XStructure *s, const char *name, void *dst, XType type, int count)
     
    boolean smaxGetBooleanField (const XStructure *s, const char *name, boolean defaultValue)
     
    double smaxGetDoubleField (const XStructure *s, const char *name, double defaultValue)
     
    long long smaxGetLongField (const XStructure *s, const char *name, long long defaultValue)
     
    char * smaxGetRawField (const XStructure *s, const char *name, char *defaultValue)
     
    double smaxPullDouble (const char *table, const char *key)
     
    double smaxPullDoubleDefault (const char *table, const char *key, double defaultValue)
     
    double * smaxPullDoubles (const char *table, const char *key, XMeta *meta, int *n)
     
    int smaxPullInt (const char *table, const char *key, int defaultValue)
     
    int * smaxPullInts (const char *table, const char *key, XMeta *meta, int *n)
     
    long long smaxPullLong (const char *table, const char *key, long long defaultValue)
     
    long long * smaxPullLongs (const char *table, const char *key, XMeta *meta, int *n)
     
    char * smaxPullRaw (const char *table, const char *key, XMeta *meta, int *status)
     
    char * smaxPullString (const char *table, const char *key)
     
    char ** smaxPullStrings (const char *table, const char *key, XMeta *meta, int *n)
     
    XStructure * smaxPullStruct (const char *id, XMeta *meta, int *status)
     
    int smaxShareBoolean (const char *table, const char *key, boolean value)
     
    int smaxShareBooleans (const char *table, const char *key, const boolean *values, int n)
     
    int smaxShareBytes (const char *table, const char *key, const char *values, int n)
     
    int smaxShareDouble (const char *table, const char *key, double value)
     
    int smaxShareDoubles (const char *table, const char *key, const double *values, int n)
     
    int smaxShareFloats (const char *table, const char *key, const float *values, int n)
     
    int smaxShareHex (const char *table, const char *key, long long value)
     
    int smaxShareInt (const char *table, const char *key, long long value)
     
    int smaxShareInts (const char *table, const char *key, const int *values, int n)
     
    int smaxShareLongs (const char *table, const char *key, const long long *values, int n)
     
    int smaxShareShorts (const char *table, const char *key, const short *values, int n)
     
    int smaxShareString (const char *table, const char *key, const char *sValue)
     
    int smaxShareStrings (const char *table, const char *key, const char **sValues, int n)
     
    int smaxWaitOnSubscribed (const char *table, const char *key, int timeout)
     
    int smaxWaitOnSubscribedGroup (const char *matchTable, char **changedKey, int timeout)
     
    int smaxWaitOnSubscribedVar (const char *matchKey, char **changedTable, int timeout)
     
    +

    Detailed Description

    +

    A set of functions for simplified access to SMA-X for specific variable types.

    +
    Date
    Apr 6, 2019
    +
    Author
    Attila Kovacs
    +

    Function Documentation

    + +

    ◆ smaxCreate1DField()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    XField * smaxCreate1DField (const char * name,
    XType type,
    int size,
    const void * value )
    +
    +

    Creates a field for 1-D array of a given name and type using specified native values. It is like xCreate1DField() except that the field is created in serialized form.

    +
    Parameters
    + + + + + +
    nameField name
    typeStorage type, e.g. X_INT.
    sizeArray size.
    valuePointer to the native array in memory.
    +
    +
    +
    Returns
    A newly created field with the supplied data, or NULL if there was an error.
    +
    See also
    xSetField()
    + +

    References smaxCreateField().

    + +
    +
    + +

    ◆ smaxCreateBooleanField()

    + +
    +
    + + + + + + + + + + + +
    XField * smaxCreateBooleanField (const char * name,
    boolean value )
    +
    +

    Creates a field holding a single boolean value. It is like xCreateBooleanField() except that the field is created in serialized form.

    +
    Parameters
    + + + +
    nameField name
    valueAssociated value
    +
    +
    +
    Returns
    A newly created field with the supplied data, or NULL if there was an error.
    +
    See also
    xSetField()
    + +

    References smaxCreateScalarField().

    + +
    +
    + +

    ◆ smaxCreateDoubleField()

    + +
    +
    + + + + + + + + + + + +
    XField * smaxCreateDoubleField (const char * name,
    double value )
    +
    +

    Creates a field holding a single double-precision value. It is like xCreateDoubleField() except that the field is created in serialized form.

    +
    Parameters
    + + + +
    nameField name
    valueAssociated value
    +
    +
    +
    Returns
    A newly created field with the supplied data, or NULL if there was an error.
    +
    See also
    xSetField()
    + +

    References smaxCreateScalarField().

    + +
    +
    + +

    ◆ smaxCreateIntField()

    + +
    +
    + + + + + + + + + + + +
    XField * smaxCreateIntField (const char * name,
    int value )
    +
    +

    Creates a field holding a single integer value. It is like xCreateIntField() except that the field is created in serialized form.

    +
    Parameters
    + + + +
    nameField name
    valueAssociated value
    +
    +
    +
    Returns
    A newly created field with the supplied data, or NULL if there was an error.
    +
    See also
    xSetField()
    + +

    References smaxCreateScalarField().

    + +
    +
    + +

    ◆ smaxCreateLongField()

    + +
    +
    + + + + + + + + + + + +
    XField * smaxCreateLongField (const char * name,
    long long value )
    +
    +

    Creates a field holding a single wide (64-bit) integer value. It is like xCreateLongField() except that the field is created in serialized form.

    +
    Parameters
    + + + +
    nameField name
    valueAssociated value
    +
    +
    +
    Returns
    A newly created field with the supplied data, or NULL if there was an error.
    +
    See also
    xSetField()
    + +

    References smaxCreateScalarField().

    + +
    +
    + +

    ◆ smaxCreateScalarField()

    + +
    +
    + + + + + + + + + + + + + + + + +
    XField * smaxCreateScalarField (const char * name,
    XType type,
    const void * value )
    +
    +

    Creates a scalar field of a given name and type using the specified native value. It is like xCreateScalarField() except that the field is created in serialized form.

    +
    Parameters
    + + + + +
    nameField name
    typeStorage type, e.g. X_INT.
    valuePointer to the native data location in memory.
    +
    +
    +
    Returns
    A newly created scalar field with the supplied data, or NULL if there was an error.
    +
    See also
    xSetField()
    + +

    References smaxCreate1DField().

    + +
    +
    + +

    ◆ smaxCreateStringField()

    + +
    +
    + + + + + + + + + + + +
    XField * smaxCreateStringField (const char * name,
    const char * value )
    +
    +

    Creates a field holding a single string value. It is like xCreateStringField() except that the field is created in serialized form.

    +
    Parameters
    + + + +
    nameField name
    valueAssociated value
    +
    +
    +
    Returns
    A newly created field referencing the supplied string, or NULL if there was an error.
    + +

    References smaxCreateScalarField().

    + +
    +
    + +

    ◆ smaxGetArrayField()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    int smaxGetArrayField (const XStructure * s,
    const char * name,
    void * dst,
    XType type,
    int count )
    +
    +

    Gets the data of an SMA-X structure field as an array of values of the specified type and element count. The field's data will be truncated or padded with zeroes to provide the requested element count always.

    +
    Parameters
    + + + + + + +
    sPointer to SMA-X structure
    nameField name
    [out]dstArray to return values in.
    typeType of data.
    countNumber of elements in return array. The field data will be truncated or padded as necessary.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_STRUCT_INVALID if the input structure is NULL, X_NULL if dst is NULL, X_SIZE_INVALID if n is 0 or negative, X_NAME_INVALID if the structure does not have a field by the specified name, or else an error returned by smaxStringtoValues().
    + +

    References smaxStringToValues().

    + +
    +
    + +

    ◆ smaxGetBooleanField()

    + +
    +
    + + + + + + + + + + + + + + + + +
    boolean smaxGetBooleanField (const XStructure * s,
    const char * name,
    boolean defaultValue )
    +
    +

    Returns the first value in a structure's field as an integer, or the specified default value if there is no such field in the structure, or the content cannot be parse into an integer.

    +
    Parameters
    + + + + +
    sPointer to the XStructure.
    nameField name
    defaultValueValue to return if no corresponding integer field value.
    +
    +
    +
    Returns
    The (first) field value as a long long, or the default value if there is no such field.
    +
    See also
    xGetField()
    + +
    +
    + +

    ◆ smaxGetDoubleField()

    + +
    +
    + + + + + + + + + + + + + + + + +
    double smaxGetDoubleField (const XStructure * s,
    const char * name,
    double defaultValue )
    +
    +

    Returns the first value in a structure's field as a double precision float, or the specified default value if there is no such field in the structure, or the content cannot be parse into an double.

    +
    Parameters
    + + + + +
    sPointer to the XStructure.
    nameField name
    defaultValueValue to return if no corresponding integer field value.
    +
    +
    +
    Returns
    The (first) field value as a double, or the specified default if there is no such field.
    +
    See also
    xGetField()
    + +
    +
    + +

    ◆ smaxGetLongField()

    + +
    +
    + + + + + + + + + + + + + + + + +
    long long smaxGetLongField (const XStructure * s,
    const char * name,
    long long defaultValue )
    +
    +

    Returns the first value in a structure's field as an integer, or the specified default value if there is no such field in the structure, or the content cannot be parse into an integer.

    +
    Parameters
    + + + + +
    sPointer to the XStructure.
    nameField name
    defaultValueValue to return if no corresponding integer field value.
    +
    +
    +
    Returns
    The (first) field value as a long long, or the default value if there is no such field.
    +
    See also
    xGetField()
    + +
    +
    + +

    ◆ smaxGetRawField()

    + +
    +
    + + + + + + + + + + + + + + + + +
    char * smaxGetRawField (const XStructure * s,
    const char * name,
    char * defaultValue )
    +
    +

    Returns the string value in a structure's field, or the specified default value if there is no such field in the structure.

    +
    Parameters
    + + + + +
    sPointer to the XStructure.
    nameField name
    defaultValueValue to return if no corresponding integer field value.
    +
    +
    +
    Returns
    The field's string (raw) value, or the specified default if there is no such field.
    +
    See also
    xGetField()
    + +
    +
    + +

    ◆ smaxPullDouble()

    + +
    +
    + + + + + + + + + + + +
    double smaxPullDouble (const char * table,
    const char * key )
    +
    +

    Returns a single floating-point value for a given SMA-X variable, or a NAN if the value could not be retrieved.

    +
    Parameters
    + + + +
    tableHash table name.
    keyVariable name under which the data is stored.
    +
    +
    +
    Returns
    The floating-point value stored in SMA-X, or NAN if the value could not be retrieved.
    +
    See also
    smaxLazyPullDouble()
    +
    +smaxPullDoubleDefault()
    + +

    References smaxPullDoubleDefault().

    + +
    +
    + +

    ◆ smaxPullDoubleDefault()

    + +
    +
    + + + + + + + + + + + + + + + + +
    double smaxPullDoubleDefault (const char * table,
    const char * key,
    double defaultValue )
    +
    +

    Returns a single floating-point value for a given SMA-X variable, or a specified default value if the SMA-X value could not be retrieved.

    +
    Parameters
    + + + + +
    tableHash table name.
    keyVariable name under which the data is stored.
    defaultValueThe value to return in case of an error.
    +
    +
    +
    Returns
    The floating-point value stored in SMA-X, or the specified default if the value could not be retrieved.
    +
    See also
    smaxLazyPullDoubleDefault()
    +
    +smaxPullDouble()
    + +

    References smaxPull().

    + +
    +
    + +

    ◆ smaxPullDoubles()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    double * smaxPullDoubles (const char * table,
    const char * key,
    XMeta * meta,
    int * n )
    +
    +

    Returns a dynamically allocated array of doubles stored in an SMA-X variable.

    +
    Parameters
    + + + + + +
    [in]tableThe hash table name.
    [in]keyThe variable name under which the data is stored.
    [out]meta(optional) Pointer to metadata to be filled or NULL if not required.
    [out]nPointer to which the number of double is returned (if *n > 0) or else an error code.
    +
    +
    +
    Returns
    Pointer to C double[] array containing *n elements, or NULL.
    +
    See also
    smaxPullDouble()
    +
    +smaxPullFloats()
    + +
    +
    + +

    ◆ smaxPullInt()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxPullInt (const char * table,
    const char * key,
    int defaultValue )
    +
    +

    Returns a single integer value for a given SMA-X variable, or a default value if the value could not be retrieved.

    +
    Parameters
    + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    defaultValueThe value to return in case of an error.
    +
    +
    +
    Returns
    The integer value stored in SMA-X, or the specified default if the value could not be retrieved.
    +
    See also
    smaxLazyPullInt()
    +
    +smaxPullInts()
    +
    +smaPullLong()
    + +

    References smaxPull().

    + +
    +
    + +

    ◆ smaxPullInts()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int * smaxPullInts (const char * table,
    const char * key,
    XMeta * meta,
    int * n )
    +
    +

    Returns a dynamically allocated array of integers stored in an SMA-X variable.

    +
    Parameters
    + + + + + +
    [in]tableThe hash table name.
    [in]keyThe variable name under which the data is stored.
    [out]meta(optional) Pointer to metadata to be filled or NULL if not required.
    [out]nPointer to which the number of integers is returned (if *n > 0) or else an error code.
    +
    +
    +
    Returns
    Pointer to C int[] array containing *n elements, or NULL.
    +
    See also
    smaxPullShorts()
    +
    +smaxPullLongs()
    +
    +smaxPullInt()
    + +
    +
    + +

    ◆ smaxPullLong()

    + +
    +
    + + + + + + + + + + + + + + + + +
    long long smaxPullLong (const char * table,
    const char * key,
    long long defaultValue )
    +
    +

    Returns a single integer value for a given SMA-X variable, or a default value if the value could not be retrieved.

    +
    Parameters
    + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    defaultValueThe value to return in case of an error.
    +
    +
    +
    Returns
    The integer value stored in SMA-X, or the specified default if the value could not be retrieved.
    +
    See also
    smaxLazyPullLong()
    +
    +smaxPullLongs()
    +
    +smaxPullInt()
    + +

    References smaxPull().

    + +
    +
    + +

    ◆ smaxPullLongs()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    long long * smaxPullLongs (const char * table,
    const char * key,
    XMeta * meta,
    int * n )
    +
    +

    Returns a dynamically allocated array of long long (int64) integers stored in an SMA-X variable.

    +
    Parameters
    + + + + + +
    [in]tableThe hash table name.
    [in]keyThe variable name under which the data is stored.
    [out]meta(optional) Pointer to metadata to be filled or NULL if not required.
    [out]nPointer to which the number of integers is returned (if *n > 0) or else an error code.
    +
    +
    +
    Returns
    Pointer to C int[] array containing *n elements, or NULL.
    +
    See also
    smaxPullInts()
    +
    +smaxPullShorts()
    +
    +smaxPullLong()
    + +
    +
    + +

    ◆ smaxPullRaw()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    char * smaxPullRaw (const char * table,
    const char * key,
    XMeta * meta,
    int * status )
    +
    +

    Returns a dynamically allocated buffer with the raw string value stored in SMA-X. This call can also be used to get single string values from SMA-X, since for single string the stored raw value is simply the string itself. However, to properly retrieve string arrays, you want to use smaxPullStrings() instead.

    +
    Parameters
    + + + + + +
    [in]tableThe hash table name.
    [in]keyThe variable name under which the data is stored.
    [out]meta(optional) Pointer to metadata to be filled or NULL if not required.
    [out]statusPointer int which an error status is returned.
    +
    +
    +
    Returns
    Pointer to C array containing the elements of the specified type, or NULL.
    +
    See also
    smaxPullStrings()
    + +

    References smaxPull().

    + +
    +
    + +

    ◆ smaxPullString()

    + +
    +
    + + + + + + + + + + + +
    char * smaxPullString (const char * table,
    const char * key )
    +
    +

    Returns a single string value for a given SMA-X variable, or a NULL if the value could not be retrieved.

    +
    Parameters
    + + + +
    tableHash table name.
    keyVariable name under which the data is stored.
    +
    +
    +
    Returns
    Pouinter to the string value stored in SMA-X, or NULL if the value could not be retrieved.
    +
    See also
    smaxLazyPullString()
    +
    +smaxPullStrings()
    + +

    References smaxPull().

    + +
    +
    + +

    ◆ smaxPullStrings()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    char ** smaxPullStrings (const char * table,
    const char * key,
    XMeta * meta,
    int * n )
    +
    +

    Returns an array of pointers to individuals strings inside the retrieved contiguous data buffer. Thus, to discard the returned data after use, you must first discard the underlying buffer (as pointed by the first element) before discarding the array of pointers themselves. E.g.:

    +

    char **array = smaxPullStrings("mygroup", "myfield", &meta); ... if(array != NULL) { free(array[0]); // discards the underlying contiguous buffer free(array); // discards the array of pointers. }

    +
    Parameters
    + + + + + +
    [in]tableThe hash table name.
    [in]keyThe variable name under which the data is stored.
    [out]meta(optional) Pointer to metadata to be filled or NULL if not required.
    [out]nPointer to which the number of double is returned (if *n > 0) or else an error code.
    +
    +
    +
    Returns
    Pointer to a an array of strings (char *) containing *n elements, or NULL.
    +
    See also
    smaxPullString()
    +
    +smaxPullRaw()
    + +

    References smaxGetMetaCount(), smaxPullRaw(), XMeta::storeBytes, and X_META_INIT.

    + +
    +
    + +

    ◆ smaxPullStruct()

    + +
    +
    + + + + + + + + + + + + + + + + +
    XStructure * smaxPullStruct (const char * id,
    XMeta * meta,
    int * status )
    +
    +

    Returns a dynamically allocated XStrucure for the specified hashtable in SMA-X.

    +
    Parameters
    + + + + +
    [in]idAggregated structure ID.
    [out]meta(optional) Pointer to metadata to be filled or NULL if not required.
    [out]statusPointer int which an error status is returned.
    +
    +
    +
    Returns
    Pointer to an XStructure, or NULL.
    +
    See also
    smaxLazyPullStruct()
    +
    +xDestroyStruct()
    + +

    References smaxPull().

    + +
    +
    + +

    ◆ smaxShareBoolean()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxShareBoolean (const char * table,
    const char * key,
    boolean value )
    +
    +

    Shares a single boolean value to SMA-X. All non-zero values are mapped to "1".

    +
    Parameters
    + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    valueA boolean value.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareBooleans()
    + +

    References smaxShareBooleans().

    + +
    +
    + +

    ◆ smaxShareBooleans()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxShareBooleans (const char * table,
    const char * key,
    const boolean * values,
    int n )
    +
    +

    Shares an array of boolean values to SMA-X. All non-zero values are mapped to "1".

    +
    Parameters
    + + + + + +
    tableHash table name.
    keyVariable name under which the data is stored.
    valuesPointer to boolean[] array.
    nNumber of elements in array to share.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareBoolean()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxShareBytes()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxShareBytes (const char * table,
    const char * key,
    const char * values,
    int n )
    +
    +

    Shares a binary sequence to SMA-X.

    +
    Parameters
    + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    valuespointer to the byte buffer.
    nNumber of bytes in buffer to share.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareShorts()
    +
    +smaxShareInts()
    +
    +smaxShareLongs()
    +
    +smaxShareInt()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxShareDouble()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxShareDouble (const char * table,
    const char * key,
    double value )
    +
    +

    Shares a single floating point value to SMA-X.

    +
    Parameters
    + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    valuefloating-point value.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareDoubles()
    +
    +smaxShareFloats()
    + +

    References smaxShareDoubles().

    + +
    +
    + +

    ◆ smaxShareDoubles()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxShareDoubles (const char * table,
    const char * key,
    const double * values,
    int n )
    +
    +

    Shares an array of doubles to SMA-X.

    +
    Parameters
    + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    valuesPointer to double[] array.
    nNumber of elements in array to share.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareDouble()
    +
    +smaxShareFloats()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxShareFloats()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxShareFloats (const char * table,
    const char * key,
    const float * values,
    int n )
    +
    +

    Shares an array of floats to SMA-X.

    +
    Parameters
    + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    valuesPointer to float[] array.
    nNumber of elements in array to share.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareDouble()
    +
    +smaxShareDoubles()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxShareHex()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxShareHex (const char * table,
    const char * key,
    long long value )
    +
    +

    Shares a single integer value to SMA-X in a hexadecimal representatin.

    +
    Parameters
    + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    valueInteger value.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareInt()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxShareInt()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxShareInt (const char * table,
    const char * key,
    long long value )
    +
    +

    Shares a single integer value to SMA-X.

    +
    Parameters
    + + + + +
    tableHash table name.
    keyVariable name under which the data is stored.
    valueInteger value.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareHex()
    +
    +smaxShareInts()
    + +

    References smaxShareLongs().

    + +
    +
    + +

    ◆ smaxShareInts()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxShareInts (const char * table,
    const char * key,
    const int * values,
    int n )
    +
    +

    Shares an array of long integers to SMA-X.

    +
    Parameters
    + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    valuesPointer to int[] array.
    nNumber of elements in array to share.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareLongs()
    +
    +smaxShareShorts()
    +
    +smaxShareBytes()
    +
    +smaxShareInt()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxShareLongs()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxShareLongs (const char * table,
    const char * key,
    const long long * values,
    int n )
    +
    +

    Shares an array of wide integers to SMA-X.

    +
    Parameters
    + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    valuesPointer to long long[] array.
    nNumber of elements in array to share.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareInts()
    +
    +smaxShareShorts()
    +
    +smaxShareBytes()
    +
    +smaxShareInt()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxShareShorts()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxShareShorts (const char * table,
    const char * key,
    const short * values,
    int n )
    +
    +

    Shares an array of shorts to SMA-X.

    +
    Parameters
    + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    valuesPointer to short[] array.
    nNumber of elements in array to share.
    +
    +
    +
    Returns
    X_SUCCESS(0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareInt()
    +
    +smaxShareBytes()
    +
    +smaxShareInts()
    +
    +smaxShareLongs()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxShareString()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxShareString (const char * table,
    const char * key,
    const char * sValue )
    +
    +

    Shares a single string value to SMA-X.

    +
    Parameters
    + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    sValuePointer to string.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareStrings()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxShareStrings()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxShareStrings (const char * table,
    const char * key,
    const char ** sValues,
    int n )
    +
    +

    Shares an array of strings to SMA-X.

    +
    Parameters
    + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    sValuesPointer to array of string pointers.
    nNumber of elements in array to share.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareString()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxWaitOnSubscribed()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxWaitOnSubscribed (const char * table,
    const char * key,
    int timeout )
    +
    +

    Waits for a specific pushed entry. There must be an active subscription that includes the specified group & variable, or else the call will block indefinitely.

    +
    Parameters
    + + + + +
    tableHash table name
    keyVariable name to wait on.
    timeout(s) Timeout value. 0 or negative values result in an indefinite wait.
    +
    +
    +
    Returns
    X_SUCCESS (0) if the variable was updated on some host (or owner). X_NO_INIT if the SMA-X sharing was not initialized via smaxConnect(). X_GROUP_INVALID if the 'group' argument is NULL; X_NAME_INVALID if the 'key' argument is NULL. X_REL_PREMATURE if smaxReleaseWaits() was called.
    +
    See also
    smaxSubscribe()
    +
    +smaxWaitOnSubscribed()
    +
    +smaxWaitOnSubscribedGroup()
    +
    +smaxWaitOnSubscribedVar()
    +
    +smaxWaitOnAnySubscribed()
    +
    +smaxReleaseWaits()
    + +
    +
    + +

    ◆ smaxWaitOnSubscribedGroup()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxWaitOnSubscribedGroup (const char * matchTable,
    char ** changedKey,
    int timeout )
    +
    +

    Waits for changes on a specific group. The must be an active subscription including that group, or else the call will block indefinitely.

    +
    Parameters
    + + + + +
    [in]matchTableHash table name (e.g. owner ID) to wait on.
    [out]changedKeyPointer to the string that holds the name of the variable which unblocked the wait or which is set to NULL. The lease of the buffer is for the call only. The caller should copy its content if persistent storage is required.
    [in]timeout(s) Timeout value. 0 or negative values result in an indefinite wait.
    +
    +
    +
    Returns
    X_SUCCESS (0) if a variable was updated on the host. X_NO_INIT if the SMA-X sharing was not initialized via smaxConnect(). X_GROUP_INVALID if the table name to match is invalid. X_REL_PREMATURE if smaxReleaseWaits() was called.
    +
    See also
    smaxSubscribe()
    +
    +smaxWaitOnSubscribedVar()
    +
    +smaxWaitOnSubscribed()
    +
    +smaxWaitOnAnySubscribed()
    +
    +smaxReleaseWaits()
    + +
    +
    + +

    ◆ smaxWaitOnSubscribedVar()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxWaitOnSubscribedVar (const char * matchKey,
    char ** changedTable,
    int timeout )
    +
    +

    Waits for a specific pushed variable from any group/table. There must be an active subscription that includes the specified variable in one or more groups/tables, or else the call will block indefinitely.

    +
    Parameters
    + + + + +
    [in]matchKeyVariable name to wait on.
    [out]changedTablePointer to the string that holds the name of the table which unblocked the wait or which is set to NULL. The lease of the buffer is for the call only. The caller should copy its content if persistent storage is required.
    [in]timeout(s) Timeout value. 0 or negative values result in an indefinite wait.
    +
    +
    +
    Returns
    X_SUCCESS (0) if the variable was updated on some host (or owner). X_NO_INIT if the SMA-X sharing was not initialized via smaxConnect(). X_NAME_INVALID if the 'key' argument is NULL. X_REL_PREMATURE if smaxReleaseWaits() was called.
    +
    See also
    smaxSubscribe()
    +
    +smaxWaitOnSubscribedGroup()
    +
    +smaxWaitOnSubscribed()
    +
    +smaxWaitOnAnySubscribed()
    +
    +smaxReleaseWaits()
    + +
    +
    +
    +
    + + + + diff --git a/apidoc/html/smax-easy_8c.js b/apidoc/html/smax-easy_8c.js new file mode 100644 index 0000000..e8c20f5 --- /dev/null +++ b/apidoc/html/smax-easy_8c.js @@ -0,0 +1,42 @@ +var smax_easy_8c = +[ + [ "smaxCreate1DField", "smax-easy_8c.html#afba357d35d2a1f13d0cf06f5ff708a99", null ], + [ "smaxCreateBooleanField", "smax-easy_8c.html#a13e357c3f20c0799fba6bc6c2a16c520", null ], + [ "smaxCreateDoubleField", "smax-easy_8c.html#afa9c9ec0f47236c0c560eee724b809d6", null ], + [ "smaxCreateIntField", "smax-easy_8c.html#afcb9ce5f154eef8eccdb0930ec4d613d", null ], + [ "smaxCreateLongField", "smax-easy_8c.html#a23b55eae1ce68356073ea5b191f915e5", null ], + [ "smaxCreateScalarField", "smax-easy_8c.html#a61a3760159e6867cdb55b5995435633c", null ], + [ "smaxCreateStringField", "smax-easy_8c.html#aa5c7661e29f4f1ba62f457c7138f2654", null ], + [ "smaxGetArrayField", "smax-easy_8c.html#a10525c664231e85f3cd9a592915b8919", null ], + [ "smaxGetBooleanField", "smax-easy_8c.html#a555c133ddd7aee3cf481f9e5e15e3d43", null ], + [ "smaxGetDoubleField", "smax-easy_8c.html#ab7c45d4512c22c24153763aa9e227b68", null ], + [ "smaxGetLongField", "smax-easy_8c.html#a8035211bd1fe17551a1517560b2547c4", null ], + [ "smaxGetRawField", "smax-easy_8c.html#ada517cdb7737bb38695e2a343123583b", null ], + [ "smaxPullDouble", "smax-easy_8c.html#aa143c2385f210cdd772f014939e1411e", null ], + [ "smaxPullDoubleDefault", "smax-easy_8c.html#a1d30cb3f0a48b567657975a104a1088f", null ], + [ "smaxPullDoubles", "smax-easy_8c.html#a6e5df36b7eee3944b1ef07edb7f9647d", null ], + [ "smaxPullInt", "smax-easy_8c.html#a42685e249ca24359b0f3f2a04a99b16b", null ], + [ "smaxPullInts", "smax-easy_8c.html#a8cdf0e4d01eaa160b8c96593ce32f4ff", null ], + [ "smaxPullLong", "smax-easy_8c.html#aebedc01880d4253e74b8bde565de00d5", null ], + [ "smaxPullLongs", "smax-easy_8c.html#a843fa579fa26190335aeebb87be63203", null ], + [ "smaxPullRaw", "smax-easy_8c.html#a0de71a90fdf235a8aee084543591244f", null ], + [ "smaxPullString", "smax-easy_8c.html#a41bdf6bb7bcb3f0d3cb1c0657f8da1c5", null ], + [ "smaxPullStrings", "smax-easy_8c.html#abc833f0d89e672507e0baeb146e8776b", null ], + [ "smaxPullStruct", "smax-easy_8c.html#a30a2212f19ab2cbf60ea348110475948", null ], + [ "smaxShareBoolean", "smax-easy_8c.html#a294640494c2d892dfb4944cd9da7729a", null ], + [ "smaxShareBooleans", "smax-easy_8c.html#ad4ddc1226e77667c74dd0c3e0cff56a0", null ], + [ "smaxShareBytes", "smax-easy_8c.html#a9274e66d69bf41bbe291bbadbb619acc", null ], + [ "smaxShareDouble", "smax-easy_8c.html#acfbfd2b9a23305d75e45541c5177e42a", null ], + [ "smaxShareDoubles", "smax-easy_8c.html#a1195017071e3733c0ff9c9f6e704e593", null ], + [ "smaxShareFloats", "smax-easy_8c.html#ace410207bfb5ba9211dc644f7dd2768d", null ], + [ "smaxShareHex", "smax-easy_8c.html#a9efb328571eb7aac0cec75b55676c4e0", null ], + [ "smaxShareInt", "smax-easy_8c.html#adeb667a3e72acedee7d03eb246b8e1ae", null ], + [ "smaxShareInts", "smax-easy_8c.html#acc2181d635e635e330f6e01b7643dadb", null ], + [ "smaxShareLongs", "smax-easy_8c.html#a179730ae8cc7517c96b3e7efb81411fb", null ], + [ "smaxShareShorts", "smax-easy_8c.html#a007815fcac77e840c851a54f97d575ae", null ], + [ "smaxShareString", "smax-easy_8c.html#a5c9657c01a9b8a324a9a1d318dd18e5b", null ], + [ "smaxShareStrings", "smax-easy_8c.html#a63c421116ca043f2d0899b83d8aa91f9", null ], + [ "smaxWaitOnSubscribed", "smax-easy_8c.html#a0e116b41cf8cfbca058dba8476b5d573", null ], + [ "smaxWaitOnSubscribedGroup", "smax-easy_8c.html#af6cae99a805bf84e98390e0bea2470b7", null ], + [ "smaxWaitOnSubscribedVar", "smax-easy_8c.html#af54b8b5d2e79eda86b3349c3c138331c", null ] +]; \ No newline at end of file diff --git a/apidoc/html/smax-lazy_8c.html b/apidoc/html/smax-lazy_8c.html new file mode 100644 index 0000000..cddd654 --- /dev/null +++ b/apidoc/html/smax-lazy_8c.html @@ -0,0 +1,620 @@ + + + + + + + +smax-clib: src/smax-lazy.c File Reference + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + +
    +
    smax-clib v0.9 +
    +
    A C/C++ client library for SMA-X
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    + +
    smax-lazy.c File Reference
    +
    +
    + +

    A set of functions to support the efficient retrieval of lazy variables, that is variables that change infrequently, from the SMA-X database. Rather than querying the database on every call, the first lazy pull of a variable initiates monitoring for updates. The pull requests will return the current state of the variable at all times, but it generates minimal network traffic only when the underlying value in the database is changed. +More...

    + + + + + + + + + + + + + + + + + + + + + + + + + + +

    +Functions

    int smaxGetLazyCached (const char *table, const char *key, XType type, int count, void *value, XMeta *meta)
     
    int smaxGetLazyUpdateCount (const char *table, const char *key)
     
    int smaxLazyCache (const char *table, const char *key, XType type)
     
    int smaxLazyEnd (const char *table, const char *key)
     
    int smaxLazyFlush ()
     
    int smaxLazyPull (const char *table, const char *key, XType type, int count, void *value, XMeta *meta)
     
    int smaxLazyPullChars (const char *table, const char *key, char *buf, int n)
     
    double smaxLazyPullDouble (const char *table, const char *key)
     
    double smaxLazyPullDoubleDefault (const char *table, const char *key, double defaultValue)
     
    long long smaxLazyPullLong (const char *table, const char *key, long long defaultValue)
     
    char * smaxLazyPullString (const char *table, const char *key)
     
    int smaxLazyPullStruct (const char *id, XStructure *s)
     
    +

    Detailed Description

    +

    A set of functions to support the efficient retrieval of lazy variables, that is variables that change infrequently, from the SMA-X database. Rather than querying the database on every call, the first lazy pull of a variable initiates monitoring for updates. The pull requests will return the current state of the variable at all times, but it generates minimal network traffic only when the underlying value in the database is changed.

    +
    Date
    Jun 24, 2019
    +
    Author
    Attila Kovacs
    +

    Function Documentation

    + +

    ◆ smaxGetLazyCached()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    int smaxGetLazyCached (const char * table,
    const char * key,
    XType type,
    int count,
    void * value,
    XMeta * meta )
    +
    +

    Retrieve a variable from the local cache (if available), or else pull from the SMA-X database. If local caching was not previously eanbled, it will be enabled with this call, so that subsequent calls will always return data from the locally updated cache with minimal overhead and effectively no latency.

    +
    Parameters
    + + + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    typeThe SMA-X variable type, e.g. X_FLOAT or X_CHARS(40), of the buffer.
    countThe number of elements to retrieve
    valuePointer to the native data buffer in which to restore values
    metaOptional metadata pointer, or NULL if metadata is not required.
    +
    +
    +
    Returns
    X_SUCCESS (0), or X_NO_SERVICE is SMA-X is not accessible, or another error (<0) from smax.h or xchange.h.
    +
    See also
    sa smaxLazyCache()
    +
    +sa smaxLaxyPull()
    + +
    +
    + +

    ◆ smaxGetLazyUpdateCount()

    + +
    +
    + + + + + + + + + + + +
    int smaxGetLazyUpdateCount (const char * table,
    const char * key )
    +
    +

    Returns the actual number of times a variable has been updated from SMA-X. It may be useful information when deciding if lazy pulling is appropriate (it is if the number of pull requests exceeds the actual number of transfers significantly).

    +
    Parameters
    + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    +
    +
    +
    Returns
    The number of times a variable has been updated, or -1 if the variable is not being monitored, or if the arguments are invalid.
    + +
    +
    + +

    ◆ smaxLazyCache()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxLazyCache (const char * table,
    const char * key,
    XType type )
    +
    +

    Specify that a specific variable should be cached for minimum overhead lazy access. When a variable is lazy cached its local copy is automatically updated in the background so that accessing it is always nearly instantaneous. Lazy caching is a good choice for variables that change less frequently than they are polled typically. For variables that change frequently (ans used less frequently), lazy caching is not a great choice since it consumes network bandwidth even when the variable is not being accessed.

    +

    Once a variable is lazy cached, it can be accessed instantaneously via smaxGetLazyCached() without any blocking network operations.

    +
    Parameters
    + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    typeThe SMA-X variable type, e.g. X_FLOAT or X_CHARS(40), of the buffer.
    +
    +
    +
    Returns
    X_SUCCESS (0) or X_NO_SERVICE.
    +
    See also
    smaxGetLazyCached()
    + +
    +
    + +

    ◆ smaxLazyEnd()

    + +
    +
    + + + + + + + + + + + +
    int smaxLazyEnd (const char * table,
    const char * key )
    +
    +

    Stops processing lazy updates in the background for a given variable.

    +
    Parameters
    + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    +
    +
    +
    Returns
    X_SUCCESS (0)
    +
    See also
    smaxLazyFlush()
    +
    +smaxLazyPull()
    + +
    +
    + +

    ◆ smaxLazyFlush()

    + +
    +
    + + + + + + + +
    int smaxLazyFlush ()
    +
    +

    Discards caches for all lazy variables (i.e. stops all subscriptions to variable updates, at least until the next smaxLazyPull() call). Generally speaking, it's a good idea to call this routine when one is done using a set of lazy variables for the time being, but want to avoid the tedium of calling smaxLazyEnd() individually for each of them. Note however, that after flushing the lazy caches, the fist lazy call following for each variable will inevitably result in a real SMA-X pull. So use it carefully!

    +
    Returns
    Number of monitor points flushed.
    +
    See also
    smaxLazyPull()
    +
    +smaxLazyEnd()
    + +

    References smaxRemoveSubscribers().

    + +
    +
    + +

    ◆ smaxLazyPull()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    int smaxLazyPull (const char * table,
    const char * key,
    XType type,
    int count,
    void * value,
    XMeta * meta )
    +
    +

    Poll an infrequently changing variable without stressing out the network or the SMA-X database. The first lazy pull for a variable will fetch its value from SMA-X and subscribe to update notifications. Subsequent smaxLazyPull() calls to the same variable will retrieve its value from a local cache (without contacting SMA-X) as long as it is unchanged.

    +

    Note, after you are done using a variable that has been lazy pulled, you should call smaxLazyEnd() to signal that it no longer requires to be cached and updated in the background, or call smaxLazyFlush() to flush all lazy caches for all lazy variables (if that is what you want).

    +
    Parameters
    + + + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    typeThe SMA-X variable type, e.g. X_FLOAT or X_CHARS(40), of the buffer.
    countThe number of points to retrieve into the buffer.
    valuePointer to the buffer to which the data is to be retrieved.
    metaPointer to metadata or NULL if no metadata is needed.
    +
    +
    +
    Returns
    X_SUCCESS (0) on success, or else an error code (<0) of smaxPull().
    +
    See also
    smaxLazyEnd()
    +
    +smaxLazyFlush()
    +
    +smaxPull()
    +
    +smaxQueue()
    + +
    +
    + +

    ◆ smaxLazyPullChars()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxLazyPullChars (const char * table,
    const char * key,
    char * buf,
    int n )
    +
    +

    Lazy pulls a string value into the specified string buffer.

    +
    Parameters
    + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    bufBuffer to fill with stored data
    nNumber of bytes to fill in buffer. The retrieved data will be truncated as necessary.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or the error code (<0) returned by smaxLazyPull().
    + +

    References smaxLazyPull().

    + +
    +
    + +

    ◆ smaxLazyPullDouble()

    + +
    +
    + + + + + + + + + + + +
    double smaxLazyPullDouble (const char * table,
    const char * key )
    +
    +

    Returns a single double-precision value for a given SMA-X variable, or NAN if the value could not be retrieved.

    +
    Parameters
    + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    +
    +
    +
    Returns
    The floating-point value stored in SMA-X, or NaN if the value could not be retrieved.
    +
    See also
    smaxLazyPullDoubleDefault()
    +
    +smaxPullDouble()
    + +

    References smaxLazyPullDoubleDefault().

    + +
    +
    + +

    ◆ smaxLazyPullDoubleDefault()

    + +
    +
    + + + + + + + + + + + + + + + + +
    double smaxLazyPullDoubleDefault (const char * table,
    const char * key,
    double defaultValue )
    +
    +

    Returns a single double-precision value for a given SMA-X variable, or a default value if the value could not be retrieved.

    +
    Parameters
    + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    defaultValueThe value to return in case of an error.
    +
    +
    +
    Returns
    The floating-point value stored in SMA-X, or the specified default if the value could not be retrieved.
    +
    See also
    smaxLazyPullDouble()
    +
    +smaxPullDoubleDefault()
    + +

    References smaxLazyPull().

    + +
    +
    + +

    ◆ smaxLazyPullLong()

    + +
    +
    + + + + + + + + + + + + + + + + +
    long long smaxLazyPullLong (const char * table,
    const char * key,
    long long defaultValue )
    +
    +

    Returns a single integer value for a given SMA-X variable, or a default value if the value could not be retrieved.

    +
    Parameters
    + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    defaultValueThe value to return in case of an error.
    +
    +
    +
    Returns
    The long integer value stored in SMA-X, or the specified default if the value could not be retrieved.
    +
    See also
    smaxPullLong()
    + +

    References smaxLazyPull().

    + +
    +
    + +

    ◆ smaxLazyPullString()

    + +
    +
    + + + + + + + + + + + +
    char * smaxLazyPullString (const char * table,
    const char * key )
    +
    +

    Returns a single string value for a given SMA-X variable, or a NULL if the value could not be retrieved.

    +
    Parameters
    + + + +
    tableHash table name.
    keyVariable name under which the data is stored.
    +
    +
    +
    Returns
    Pointer to the string value stored in SMA-X, or NULL if the value could not be retrieved.
    +
    See also
    smaxPullString()
    + +

    References smaxLazyPull().

    + +
    +
    + +

    ◆ smaxLazyPullStruct()

    + +
    +
    + + + + + + + + + + + +
    int smaxLazyPullStruct (const char * id,
    XStructure * s )
    +
    +

    Lazy pulls data into a structure, discarding any prior data that the structure might contain.

    +
    Parameters
    + + + +
    [in]idAggregate structure ID.
    [out]sDestination structure to populate with the retrieved fields
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or the error code (<0) returned by smaxLazyPull().
    +
    See also
    smaxPullStruct()
    +
    +xCreateStruct()
    + +

    References smaxLazyPull().

    + +
    +
    +
    +
    + + + + diff --git a/apidoc/html/smax-lazy_8c.js b/apidoc/html/smax-lazy_8c.js new file mode 100644 index 0000000..14580f9 --- /dev/null +++ b/apidoc/html/smax-lazy_8c.js @@ -0,0 +1,15 @@ +var smax_lazy_8c = +[ + [ "smaxGetLazyCached", "smax-lazy_8c.html#a42c08f13c70400dc1225d4097342ded0", null ], + [ "smaxGetLazyUpdateCount", "smax-lazy_8c.html#aeca4aa02259278b240e4131f7edea816", null ], + [ "smaxLazyCache", "smax-lazy_8c.html#a18027e41c40722011815bc878857e3d0", null ], + [ "smaxLazyEnd", "smax-lazy_8c.html#a167a60b494fa9ec5b046f9da796f18b5", null ], + [ "smaxLazyFlush", "smax-lazy_8c.html#af3d0cff3f8a6ab745907f4544981fdd1", null ], + [ "smaxLazyPull", "smax-lazy_8c.html#ab50222d7bbaa985fd6d004d67b0269ce", null ], + [ "smaxLazyPullChars", "smax-lazy_8c.html#a45d5c86c16869e5208b9c5cf688adc53", null ], + [ "smaxLazyPullDouble", "smax-lazy_8c.html#a31ed83292a29d69e1c9635b21aae7561", null ], + [ "smaxLazyPullDoubleDefault", "smax-lazy_8c.html#ac823bc3c1ee1bdbc4c330366fc246c8e", null ], + [ "smaxLazyPullLong", "smax-lazy_8c.html#a03e3bb5c838dc621f8c0ba5fb6fe5f87", null ], + [ "smaxLazyPullString", "smax-lazy_8c.html#a38d33bcbf9f2f73adbaf040996279859", null ], + [ "smaxLazyPullStruct", "smax-lazy_8c.html#af96429709d1b029a8db74cb7407f9ffb", null ] +]; \ No newline at end of file diff --git a/apidoc/html/smax-messages_8c.html b/apidoc/html/smax-messages_8c.html new file mode 100644 index 0000000..e728c08 --- /dev/null +++ b/apidoc/html/smax-messages_8c.html @@ -0,0 +1,498 @@ + + + + + + + +smax-clib: src/smax-messages.c File Reference + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + +
    +
    smax-clib v0.9 +
    +
    A C/C++ client library for SMA-X
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    + +
    smax-messages.c File Reference
    +
    +
    + +

    Simple API for sending and receiving program broadcast messages through SMA-X. +More...

    + + + + + + + + +

    +Macros

    +#define MESSAGES_ID   "messages"
     Redis PUB_SUB channel head used for program messages.
     
    +#define MESSAGES_PREFIX   MESSAGES_ID X_SEP
     Prefix for Redis PUB/SUB channel for program messages (e.g. "messages:")
     
    + + + + + + + + + + + + + + + + + + + + + + + +

    +Functions

    int smaxAddDefaultMessageProcessor (const char *host, const char *prog, const char *type)
     
    int smaxAddMessageProcessor (const char *host, const char *prog, const char *type, void(*f)(XMessage *))
     
    int smaxRemoveMessageProcessor (int id)
     
    int smaxSendDebug (const char *msg)
     
    int smaxSendDetail (const char *msg)
     
    int smaxSendError (const char *msg)
     
    int smaxSendInfo (const char *msg)
     
    int smaxSendProgress (double fraction, const char *msg)
     
    int smaxSendStatus (const char *msg)
     
    int smaxSendWarning (const char *msg)
     
    void smaxSetMessageSenderID (const char *id)
     
    +

    Detailed Description

    +

    Simple API for sending and receiving program broadcast messages through SMA-X.

    +
    Author
    Attila Kovacs
    +
    Date
    Created on 12 December 2020
    +

    Function Documentation

    + +

    ◆ smaxAddDefaultMessageProcessor()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxAddDefaultMessageProcessor (const char * host,
    const char * prog,
    const char * type )
    +
    +

    Report messages to stdout/stderr in default formats.

    +
    Parameters
    + + + + +
    hostHost name where messages originate from, or "*" or NULL if any.
    progProgram name of message originator, or "*" or NULL if any.
    typeMessage type, or "*" or NULL if any.
    +
    +
    +
    Returns
    Serial ID number (> 0) of the message processor, or X_NULL.
    + +

    References smaxAddMessageProcessor().

    + +
    +
    + +

    ◆ smaxAddMessageProcessor()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxAddMessageProcessor (const char * host,
    const char * prog,
    const char * type,
    void(*)(XMessage *) f )
    +
    +

    Adds a message processor function for a specific host (or all hosts), a specific program (or all programs), and a specific message type (or all message types).

    +
    Parameters
    + + + + + +
    hostHost name where messages originate from, or "*" or NULL if any.
    progProgram name of message originator, or "*" or NULL if any.
    typeMessage type, or "*" or NULL if any.
    fCallback function
    +
    +
    +
    Returns
    Serial ID number (> 0) of the message processor, or X_NULL if callback function is null, or X_FAILURE if malloc failed.
    +
    See also
    smaxRemoveMessageProcessor()
    + +

    References MESSAGES_PREFIX, smaxGetRedis(), and smaxRemoveMessageProcessor().

    + +
    +
    + +

    ◆ smaxRemoveMessageProcessor()

    + +
    +
    + + + + + + + +
    int smaxRemoveMessageProcessor (int id)
    +
    +

    Stops a running message processor.

    +
    Parameters
    + + +
    idMessage processor ID, as returned by smaxAddMessageProcessor()
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NULL if no message processor is running by that ID.
    +
    See also
    smaxAddMessageProcessor()
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxSendDebug()

    + +
    +
    + + + + + + + +
    int smaxSendDebug (const char * msg)
    +
    +

    Broadcast a debugging message via SMA-X (e.g. program traces).

    +
    Parameters
    + + +
    msgMessage text
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an X error.
    + +

    References SMAX_MSG_DEBUG.

    + +
    +
    + +

    ◆ smaxSendDetail()

    + +
    +
    + + + + + + + +
    int smaxSendDetail (const char * msg)
    +
    +

    Broadcast non-essential verbose informational detail via SMA-X.

    +
    Parameters
    + + +
    msgMessage text
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an X error.
    + +

    References SMAX_MSG_DETAIL.

    + +
    +
    + +

    ◆ smaxSendError()

    + +
    +
    + + + + + + + +
    int smaxSendError (const char * msg)
    +
    +

    Broadcast an error message via SMA-X. Errors should be used for an issues that impair program functionality.

    +
    Parameters
    + + +
    msgMessage text
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an X error.
    +
    See also
    smaxSendWarning();
    +
    +smaxSendDebug();
    + +

    References SMAX_MSG_ERROR.

    + +
    +
    + +

    ◆ smaxSendInfo()

    + +
    +
    + + + + + + + +
    int smaxSendInfo (const char * msg)
    +
    +

    Broadcast an informational message via SMA-X. These should be confirmations or essential information reported back to users. Non-essential information should be sent with sendDetail() instead.

    +
    Parameters
    + + +
    msgMessage text
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an X error.
    +
    See also
    sendDetail()
    +
    +sendStatus()
    + +

    References SMAX_MSG_INFO.

    + +
    +
    + +

    ◆ smaxSendProgress()

    + +
    +
    + + + + + + + + + + + +
    int smaxSendProgress (double fraction,
    const char * msg )
    +
    +

    Broadcast a progress update over SMA-X.

    +
    Parameters
    + + + +
    fraction(0.0:1.0) Completion fraction.
    msgMessage text
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an X error.
    + +

    References SMAX_MSG_DETAIL.

    + +
    +
    + +

    ◆ smaxSendStatus()

    + +
    +
    + + + + + + + +
    int smaxSendStatus (const char * msg)
    +
    +

    Broadcast a program status update via SMA-X.

    +
    Parameters
    + + +
    msgMessage text
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an X error.
    +
    See also
    sendInfo()
    + +

    References SMAX_MSG_STATUS.

    + +
    +
    + +

    ◆ smaxSendWarning()

    + +
    +
    + + + + + + + +
    int smaxSendWarning (const char * msg)
    +
    +

    Broadcast a warning message via SMA-X. Warnings should be used for any potentially problematic issues that nonetheless do not impair program functionality.

    +
    Parameters
    + + +
    msgMessage text
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an X error.
    +
    See also
    smaxSendError();
    +
    +smaxSendDebug();
    + +

    References SMAX_MSG_WARNING.

    + +
    +
    + +

    ◆ smaxSetMessageSenderID()

    + +
    +
    + + + + + + + +
    void smaxSetMessageSenderID (const char * id)
    +
    +

    Sets the sender ID for outgoing program messages. By default the sender ID is <host>:<program> for the program that calls this function, but it can be modified to use some other SMA-X style hierarchical ID also.

    +
    Parameters
    + + +
    idThe new sender ID for outgoing program messages, or NULL to reinstate the default <host>:<program> style ID. The argument is not referenced and can be deallocated as desired after the call without affecting the newly defined message ID.
    +
    +
    + +
    +
    +
    +
    + + + + diff --git a/apidoc/html/smax-messages_8c.js b/apidoc/html/smax-messages_8c.js new file mode 100644 index 0000000..e3f7003 --- /dev/null +++ b/apidoc/html/smax-messages_8c.js @@ -0,0 +1,16 @@ +var smax_messages_8c = +[ + [ "MESSAGES_ID", "smax-messages_8c.html#a7b2e3f4ba6d955bd23ae56f2a2d9a3e3", null ], + [ "MESSAGES_PREFIX", "smax-messages_8c.html#a309d33601440402f7f3fb5175864b62b", null ], + [ "smaxAddDefaultMessageProcessor", "smax-messages_8c.html#aa3e777f85e81ffb9b02dc8cc3d124a94", null ], + [ "smaxAddMessageProcessor", "smax-messages_8c.html#abaa2573fb8e85e8359c8853647c38f2f", null ], + [ "smaxRemoveMessageProcessor", "smax-messages_8c.html#a1550f0f7aed841d5576d47ec7e62e0c4", null ], + [ "smaxSendDebug", "smax-messages_8c.html#a6c8e73f27c445dedd5ba4ac5b399f8d1", null ], + [ "smaxSendDetail", "smax-messages_8c.html#a2a0607da9db140f4227524da37b3bf51", null ], + [ "smaxSendError", "smax-messages_8c.html#a7d936da43078b9be469a97a6a4bb82a8", null ], + [ "smaxSendInfo", "smax-messages_8c.html#a6056608a81e52d070dcc0f3ee96579b5", null ], + [ "smaxSendProgress", "smax-messages_8c.html#a0f32699c2148f3b09a48e84b3fa4d036", null ], + [ "smaxSendStatus", "smax-messages_8c.html#a3739383ee6770337b3bb023cfe0cc64c", null ], + [ "smaxSendWarning", "smax-messages_8c.html#a740f4a171334a6aa5d4736c15fc327e4", null ], + [ "smaxSetMessageSenderID", "smax-messages_8c.html#af3e8295bb941f68cf3177c79cd5fb4d3", null ] +]; \ No newline at end of file diff --git a/apidoc/html/smax-meta_8c.html b/apidoc/html/smax-meta_8c.html new file mode 100644 index 0000000..d75c1dc --- /dev/null +++ b/apidoc/html/smax-meta_8c.html @@ -0,0 +1,668 @@ + + + + + + + +smax-clib: src/smax-meta.c File Reference + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + +
    +
    smax-clib v0.9 +
    +
    A C/C++ client library for SMA-X
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    + +
    smax-meta.c File Reference
    +
    +
    + +

    A set of utility functions for manipulating optional static metadata. +More...

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    +Functions

    XCoordinateSystemsmaxCreateCoordinateSystem (int nAxis)
     
    void smaxDestroyCoordinateSystem (XCoordinateSystem *coords)
     
    XCoordinateAxissmaxGetCoordinateAxis (const char *id, int n)
     
    XCoordinateSystemsmaxGetCoordinateSystem (const char *table, const char *key)
     
    char * smaxGetDescription (const char *table, const char *key)
     
    char * smaxGetUnits (const char *table, const char *key)
     
    char * smaxPullMeta (const char *meta, const char *table, const char *key, int *status)
     
    double smaxPullTime (const char *table, const char *key)
     
    XType smaxPullTypeDimension (const char *table, const char *key, int *ndim, int *sizes)
     
    int smaxPushMeta (const char *meta, const char *table, const char *key, const char *value)
     
    int smaxSetCoordinateAxis (const char *id, int n, const XCoordinateAxis *axis)
     
    int smaxSetCoordinateSystem (const char *table, const char *key, const XCoordinateSystem *coords)
     
    int smaxSetDescription (const char *table, const char *key, const char *description)
     
    int smaxSetUnits (const char *table, const char *key, const char *unit)
     
    +

    Detailed Description

    +

    A set of utility functions for manipulating optional static metadata.

    +
    Date
    Mar 24, 2020
    +
    Author
    Attila Kovacs
    +

    Function Documentation

    + +

    ◆ smaxCreateCoordinateSystem()

    + +
    +
    + + + + + + + +
    XCoordinateSystem * smaxCreateCoordinateSystem (int nAxis)
    +
    +

    Creates a coordinate system with the desired dimension, and standard Cartesian coordinates with no labels, or units specified (NULL).

    +
    Parameters
    + + +
    nAxisDimension of the coordiante system, i.e. number of axes.
    +
    +
    +
    Returns
    Pointer to the new coordinate system structure, or NULL if the coordiate system could not be created as specified.
    +
    See also
    smaxDestroyCoordinateSystem()
    + +

    References XCoordinateSystem::axis, XCoordinateSystem::nAxis, and XCoordinateAxis::step.

    + +
    +
    + +

    ◆ smaxDestroyCoordinateSystem()

    + +
    +
    + + + + + + + +
    void smaxDestroyCoordinateSystem (XCoordinateSystem * coords)
    +
    +

    Deallocates a coordinate system structure.

    +
    Parameters
    + + +
    coordsPointer to the coordinate system to discard.
    +
    +
    +
    See also
    smaxCreateCoordinateSystem()
    + +

    References XCoordinateSystem::axis.

    + +
    +
    + +

    ◆ smaxGetCoordinateAxis()

    + +
    +
    + + + + + + + + + + + +
    XCoordinateAxis * smaxGetCoordinateAxis (const char * id,
    int n )
    +
    +

    Returns the n'th coordinate axis for a given SMA-X coordinate system table id.

    +
    Parameters
    + + + +
    idFully qualified SMA-X coordinate system ID.
    nThe (0-based) index of the coordinate axis
    +
    +
    +
    Returns
    Pointer to a newly allocated XCoordinateAxis structure or NULL if the axis is undefined, or could not be retrieved from the database.
    +
    See also
    smaxSetCoordinateAxis()
    + +

    References XCoordinateAxis::name, XCoordinateAxis::refIndex, XCoordinateAxis::refValue, smaxGetRedis(), XCoordinateAxis::step, and XCoordinateAxis::unit.

    + +
    +
    + +

    ◆ smaxGetCoordinateSystem()

    + +
    +
    + + + + + + + + + + + +
    XCoordinateSystem * smaxGetCoordinateSystem (const char * table,
    const char * key )
    +
    +

    Returns the coordinate system, if any, associated to a given SMA-X variable.

    +
    Parameters
    + + + +
    tableHash table name.
    keyVariable / field name in table.
    +
    +
    +
    Returns
    A newly allocated coordinate system structure, or NULL.
    +
    See also
    smaxSetCoordinateSystem()
    +
    +smaxGetCoordinateAxis()
    + +

    References XCoordinateSystem::axis, META_COORDS, XCoordinateSystem::nAxis, and smaxGetCoordinateAxis().

    + +
    +
    + +

    ◆ smaxGetDescription()

    + +
    +
    + + + + + + + + + + + +
    char * smaxGetDescription (const char * table,
    const char * key )
    +
    +

    Returns a concise description of a variable.

    +
    Parameters
    + + + +
    tableHash table name.
    keyVariable / field name in table.
    +
    +
    +
    Returns
    Variable description or NULL or empty string if the variable has no description assiciated with it.
    +
    See also
    smaxSetDescription()
    + +

    References META_DESCRIPTION, and smaxPullMeta().

    + +
    +
    + +

    ◆ smaxGetUnits()

    + +
    +
    + + + + + + + + + + + +
    char * smaxGetUnits (const char * table,
    const char * key )
    +
    +

    Returns the physical unit name, if any, for the given variable.

    +
    Parameters
    + + + +
    tableHash table name.
    keyVariable / field name in table.
    +
    +
    +
    Returns
    Unit name (e.g. "W / Hz"), or NULL or empty string if the variable has no designated physical unit.
    +
    See also
    smaxSetUnits()
    + +

    References META_UNIT, and smaxPullMeta().

    + +
    +
    + +

    ◆ smaxPullMeta()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    char * smaxPullMeta (const char * meta,
    const char * table,
    const char * key,
    int * status )
    +
    +

    Retrieves a metadata string value for a given variable from the database

    +
    Parameters
    + + + + + +
    metaRoot meta table name, usually something like "<metaname>".
    tableHash table name.
    keyVariable / field name in table.
    statusPointer to int in which to return a X_SUCCESS or an error code.
    +
    +
    +
    Returns
    The string metadata value or NULL.
    +
    See also
    setPushMeta()
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxPullTime()

    + +
    +
    + + + + + + + + + + + +
    double smaxPullTime (const char * table,
    const char * key )
    +
    +

    Retrieves the timestamp for a given variable from the database.

    +
    Parameters
    + + + +
    [in]tableHash table name (or NULL if key is an aggregate ID).
    [in]keyVariable / field name in table.
    +
    +
    +
    Returns
    (s) UNIX timestamp, as fractional seconds since 1 Jan 1970, or NAN if there was an error.
    +
    See also
    setPushMeta()
    + +

    References SMAX_TIMESTAMPS, and smaxPullMeta().

    + +
    +
    + +

    ◆ smaxPullTypeDimension()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    XType smaxPullTypeDimension (const char * table,
    const char * key,
    int * ndim,
    int * sizes )
    +
    +

    Retrieves the timestamp for a given variable from the database.

    +
    Parameters
    + + + + + +
    [in]tableHash table name (or NULL if key is an aggregate ID).
    [in]keyVariable / field name in table.
    [out]ndimPointer to integer in which to return the dimensionality of the variable, or NULL if not requested.
    [out]sizesArray to store sizes along each dimension, which should hold X_MAX_DIMS integers, or NULL if dimensions are not requested.
    +
    +
    +
    Returns
    Type of data stored under the specified table/key ID.
    +
    See also
    setPushMeta()
    + +

    References SMAX_DIMS, SMAX_TYPES, smaxPullMeta(), and smaxTypeForString().

    + +
    +
    + +

    ◆ smaxPushMeta()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxPushMeta (const char * meta,
    const char * table,
    const char * key,
    const char * value )
    +
    +

    Adds/updates metadata associated with an SMA-X variable. The data will be pushed via the Redis pipeline channel.

    +
    Parameters
    + + + + + +
    metaRoot meta table name, usually something like "<metaname>".
    tableHash table name.
    keyVariable / field name in table.
    valueMetadata string value.
    +
    +
    +
    Returns
    X_SUCCESS (0) if the metadata was successfully retrieved X_INCOMPLETE if the meatdata was successfully written but an update notification was not sent or else the return value of redisxSetValue()
    +
    See also
    smaxPullMeta(), redisxSetValue()
    + +

    References smaxGetProgramID(), and smaxGetRedis().

    + +
    +
    + +

    ◆ smaxSetCoordinateAxis()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxSetCoordinateAxis (const char * id,
    int n,
    const XCoordinateAxis * axis )
    +
    +

    Defines the n'th coordinate axis for a given SMA-X coordinate system table id.

    +
    Parameters
    + + + + +
    idFully qualified SMA-X coordinate system ID.
    nThe (0-based) index of the coordinate axis
    axisPointer to the structure describing the coordinate axis.
    +
    +
    +
    Returns
    X_SUCCESS (0) if the coordinate axis was successfully set in the database. or else the return value of redisxMultiSet().
    +
    See also
    smaxSetCoordinateAxis(), redisxMultiSet()
    + +

    References XCoordinateAxis::name, XCoordinateAxis::refIndex, XCoordinateAxis::refValue, smaxGetRedis(), XCoordinateAxis::step, and XCoordinateAxis::unit.

    + +
    +
    + +

    ◆ smaxSetCoordinateSystem()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxSetCoordinateSystem (const char * table,
    const char * key,
    const XCoordinateSystem * coords )
    +
    +

    Sets the coordinate system metadata for data in the database.

    +
    Parameters
    + + + + +
    tableHash table name.
    keyVariable / field name in table.
    coordsPointer to the coordinate system structure associated to this variable.
    +
    +
    +
    Returns
    X_SUCCESS (0) if the coordinate system was successfully sent to SMA-X or else the first error encountered by xSetCoordinateAxis()
    +
    See also
    smaxGetCoordinateSystem()
    +
    +smaxSetCoordinateAxis()
    + +

    References XCoordinateSystem::axis, META_COORDS, XCoordinateSystem::nAxis, and smaxSetCoordinateAxis().

    + +
    +
    + +

    ◆ smaxSetDescription()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxSetDescription (const char * table,
    const char * key,
    const char * description )
    +
    +

    Sets the static description for a given SMA-X variable.

    +
    Parameters
    + + + + +
    tableHash table name.
    keyVariable / field name in table.
    descriptionConcise but descriptive summary of the meaning of the variable.
    +
    +
    +
    Returns
    X_SUCCESS (0) If successful or else the return value of smaxPushMeta()
    +
    See also
    smaxSetDescription(), smaxPushMeta()
    + +

    References META_DESCRIPTION, and smaxPushMeta().

    + +
    +
    + +

    ◆ smaxSetUnits()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxSetUnits (const char * table,
    const char * key,
    const char * unit )
    +
    +

    Sets the physical unit name for a given SMA-X variable.

    +
    Parameters
    + + + + +
    tableHash table name.
    keyVariable / field name in table.
    unitStandard unit specification, e.g. "W / Hz" or "W Hz**{-1}".
    +
    +
    +
    Returns
    X_SUCCESS (0) If successful or else the return value of smaxPushMeta()
    +
    See also
    smaxGetUnits(), smaxPushMeta()
    + +

    References META_UNIT, and smaxPushMeta().

    + +
    +
    +
    +
    + + + + diff --git a/apidoc/html/smax-meta_8c.js b/apidoc/html/smax-meta_8c.js new file mode 100644 index 0000000..7ef7a24 --- /dev/null +++ b/apidoc/html/smax-meta_8c.js @@ -0,0 +1,17 @@ +var smax_meta_8c = +[ + [ "smaxCreateCoordinateSystem", "smax-meta_8c.html#a1d977e7e9eb45f9ce6cc338fdde9bd8f", null ], + [ "smaxDestroyCoordinateSystem", "smax-meta_8c.html#a92cf6cd3b3f123e21a1cee437f87126d", null ], + [ "smaxGetCoordinateAxis", "smax-meta_8c.html#a349dc6fe14a2031d679e29804d82d570", null ], + [ "smaxGetCoordinateSystem", "smax-meta_8c.html#a2920bd71f9d340422e0b1b0db4bb3201", null ], + [ "smaxGetDescription", "smax-meta_8c.html#ad7ef601ffd5fbcae7b2c05be6f6bc302", null ], + [ "smaxGetUnits", "smax-meta_8c.html#aa27e3adeb67f2328a162c80bad433f02", null ], + [ "smaxPullMeta", "smax-meta_8c.html#a0d29e7a895c1d5fdc6258ff7426b3521", null ], + [ "smaxPullTime", "smax-meta_8c.html#a6deedf594f19417bfa11b8f2cef360c4", null ], + [ "smaxPullTypeDimension", "smax-meta_8c.html#ab989b724600841b16125977bcb44ffcc", null ], + [ "smaxPushMeta", "smax-meta_8c.html#aaf4c866eb1cb30dfd70e04604f1aa6cf", null ], + [ "smaxSetCoordinateAxis", "smax-meta_8c.html#a5d59620a1646428f41b040d1a0a91554", null ], + [ "smaxSetCoordinateSystem", "smax-meta_8c.html#a04c3b8ea7ff6b8117d2dba9bf9edd52f", null ], + [ "smaxSetDescription", "smax-meta_8c.html#adcc70ef29ab29f28068ac57e40497b85", null ], + [ "smaxSetUnits", "smax-meta_8c.html#a23e6627339f6bf58e87150aa9ff0c964", null ] +]; \ No newline at end of file diff --git a/apidoc/html/smax-private_8h.html b/apidoc/html/smax-private_8h.html new file mode 100644 index 0000000..7117a8a --- /dev/null +++ b/apidoc/html/smax-private_8h.html @@ -0,0 +1,132 @@ + + + + + + + +smax-clib: include/smax-private.h File Reference + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + +
    +
    smax-clib v0.9 +
    +
    A C/C++ client library for SMA-X
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    + +
    smax-private.h File Reference
    +
    +
    + +

    A set of private SMA-X routines used by the API library but should not be exposed outside. +More...

    + + + + + + + + +

    +Macros

    +#define __XCHANGE_INTERNAL_API__
     User internal definitions.
     
    +#define RELEASEID   "<release>"
     Redis PUB/SUB channel prefix for wait release notifications.
     
    +

    Detailed Description

    +

    A set of private SMA-X routines used by the API library but should not be exposed outside.

    +
    Date
    Jun 25, 2019
    +
    Author
    Attila Kovacs
    +
    +
    + + + + diff --git a/apidoc/html/smax-private_8h.js b/apidoc/html/smax-private_8h.js new file mode 100644 index 0000000..7e38a30 --- /dev/null +++ b/apidoc/html/smax-private_8h.js @@ -0,0 +1,5 @@ +var smax_private_8h = +[ + [ "__XCHANGE_INTERNAL_API__", "smax-private_8h.html#ac36bd75f87a1614fb477a0fbcd5df1f3", null ], + [ "RELEASEID", "smax-private_8h.html#acb5965a4e56d8d90d76002bef3207ef9", null ] +]; \ No newline at end of file diff --git a/apidoc/html/smax-queue_8c.html b/apidoc/html/smax-queue_8c.html new file mode 100644 index 0000000..fc20734 --- /dev/null +++ b/apidoc/html/smax-queue_8c.html @@ -0,0 +1,377 @@ + + + + + + + +smax-clib: src/smax-queue.c File Reference + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + +
    +
    smax-clib v0.9 +
    +
    A C/C++ client library for SMA-X
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    + +
    smax-queue.c File Reference
    +
    +
    + +

    Functions to support pipelined pull requests from SMA-X. Because they don't requite a sequence of round-trips, pipelined pulls can be orders of magnitude faster than staggered regular pull requests. +More...

    + + + + + + + + + + + + + + + + +

    +Functions

    XSyncPointsmaxCreateSyncPoint ()
     
    void smaxDestroySyncPoint (XSyncPoint *s)
     
    int smaxQueue (const char *table, const char *key, XType type, int count, void *value, XMeta *meta)
     
    int smaxQueueCallback (void(*f)(void *), void *arg)
     
    int smaxSetMaxPendingPulls (int n)
     
    int smaxSync (XSyncPoint *sync, int timeoutMillis)
     
    int smaxWaitQueueComplete (int timeoutMillis)
     
    +

    Detailed Description

    +

    Functions to support pipelined pull requests from SMA-X. Because they don't requite a sequence of round-trips, pipelined pulls can be orders of magnitude faster than staggered regular pull requests.

    +
    Date
    Jun 25, 2019
    +
    Author
    Attila Kovacs
    +

    Function Documentation

    + +

    ◆ smaxCreateSyncPoint()

    + +
    +
    + + + + + + + +
    XSyncPoint * smaxCreateSyncPoint ()
    +
    +

    Creates a synchronization point that can be waited upon until all elements queued prior to creation are processed (retrieved from the database.

    +
    Returns
    Pointer to a newly created synchronization point that can be waited upon.
    +
    See also
    smaxSync()
    +
    +smaxQueue()
    +
    +smaxQueueCallback()
    + +

    References XSyncPoint::isComplete, XSyncPoint::lock, and XSyncPoint::status.

    + +
    +
    + +

    ◆ smaxDestroySyncPoint()

    + +
    +
    + + + + + + + +
    void smaxDestroySyncPoint (XSyncPoint * s)
    +
    +

    Destroys a synchronization point, releasing the memory space allocated to it.

    +
    Parameters
    + + +
    sPointer to the synchronization point to discard.
    +
    +
    + +

    References XSyncPoint::isComplete, and XSyncPoint::lock.

    + +
    +
    + +

    ◆ smaxQueue()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    int smaxQueue (const char * table,
    const char * key,
    XType type,
    int count,
    void * value,
    XMeta * meta )
    +
    +

    Queues a pull requests for pipelined data retrieval. Because pipelined pulls are executed on a separate Redis client from the one used for sharing values, e.g. via smaxShare(), there is no guarantee as to the order of this pull operation and previously initiated shares from the same thread. This would only be an issue if you are trying to use queued read to read back a value you have just shared – which is not really a good use case anyway, as it generates network traffic for not real reason. But, if you must read back a value you have shared, you probably should use a regular smaxPull() call to ensure ordering.

    +
    Parameters
    + + + + + + + +
    tableHash table name.
    keyVariable name under which the data is stored.
    typeSMA-X variable type, e.g. X_FLOAT or X_CHARS(40), of the buffer.
    countNumber of points to retrieve into the buffer.
    [out]valuePointer to the buffer to which the data is to be retrieved.
    [out]metaPointer to the corresponding metadata structure, or NULL.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful X_NAME_INVALID if the table and key are both NULL X_NULL if the value field is NULL or the return value of xQueue().
    +
    See also
    smaxPull()
    +
    +smaxLazyPull()
    +
    +smaxCreateSyncPoint()
    +
    +smaxQueueCallback()
    + +

    References SMAX_PIPE_READ_TIMEOUT_MILLIS.

    + +
    +
    + +

    ◆ smaxQueueCallback()

    + +
    +
    + + + + + + + + + + + +
    int smaxQueueCallback (void(*)(void *) f,
    void * arg )
    +
    +

    Adds a callback function to the queue to be called with the specified argument once all prior requests in the queue have been fullfilled (retrieved from the database).

    +

    As a general rule callbacks added to the pipeline should return very fast, and avoid blocking operations for the most part (using mutexes that may block for very short periods only may be excepted). If the user needs to do more processing, or make blocking calls (e.g. IO operartions) that may not return for longer periods, the callback should fire off processing in a separate thread, or else simply move the result into another asynchronous processing queue.

    +
    Parameters
    + + + +
    fThe callback function that takes a pointer argument
    argArgument to call the specified function with.
    +
    +
    +
    Returns
    X_SUCCESS (0) or else X_NULL if the function parameter is NULL.
    +
    See also
    smaxCreateSyncPoint()
    +
    +smaxQueue()
    + +
    +
    + +

    ◆ smaxSetMaxPendingPulls()

    + +
    +
    + + + + + + + +
    int smaxSetMaxPendingPulls (int n)
    +
    +

    Configures how many pull requests can be queued in when piped pulls are enabled. If the queue reaches the specified limit, no new pull requests can be submitted until responses arrive, draining the queue somewhat.

    +
    Parameters
    + + +
    nThe maximum number of pull requests that can be queued.
    +
    +
    +
    Returns
    TRUE if the argument was valid, and the queue size was set to it, otherwise FALSE
    + +
    +
    + +

    ◆ smaxSync()

    + +
    +
    + + + + + + + + + + + +
    int smaxSync (XSyncPoint * sync,
    int timeoutMillis )
    +
    +

    Waits for the queue to reach the specified sync point, up to an optional timeout limit.

    +
    Parameters
    + + + +
    syncPointer to a queued synchronization point.
    timeoutMillisAn optional timeout in milliseconds. When set to a positive value The call will be guaranteed to return in the specified interval, whether or not the pipelined reads all succeeded. The return value can be used to check for errors or if the call timed out before all data were collected. If X_TIMEDOUT is returned, smax_end_bulk_pulls() may be called again to allow more time for the queued read operations to complete. 0 or negative timeout values will cause the call to wait indefinitely until reads are complete.
    +
    +
    +
    Returns
    X_SUCCESS (0) if all reads have completed successfully, or the first read error that was enountered (e.g. RM_INVALID_KEY), or: X_TIMEDOUT if the call timed out while still awaiting data for the queued read requests. X_NULL if the SyncPoint argument is NULL, or its mutex/condition field have not been initialized. X_FAILURE if the SyncPoint's mutex has not been initialized.
    +

    or the first pull error encountered in the queue since the current batch began.

    +
    See also
    smaxCreateSyncPoint()
    +
    +smaxWaitQueueComplete()
    + +

    References XSyncPoint::isComplete, XSyncPoint::lock, and XSyncPoint::status.

    + +
    +
    + +

    ◆ smaxWaitQueueComplete()

    + +
    +
    + + + + + + + +
    int smaxWaitQueueComplete (int timeoutMillis)
    +
    +

    Waits until all queued pull requests have been retrieved from the database, or until the specified timeout it reached.

    +
    Parameters
    + + +
    timeoutMillisAn optional timeout in milliseconds. When set to a positive value The call will be guaranteed to return in the specified interval, whether or not the pipelined reads all succeeded. The return value can be used to check for errors or if the call timed out before all data were collected. If X_TIMEDOUT is returned, smax_end_bulk_pulls() may be called again to allow more time for the queued read operations to complete. 0 or negative timeout values will cause the call to wait indefinitely until reads are complete.
    +
    +
    +
    Returns
    X_SUCCESS (0) if all reads have completed successfully, or the first read error that was enountered (e.g. RM_INVALID_KEY), or: X_TIMEDOUT if the call timed out while still awaiting data for the queued read requests.
    +
    See also
    smaxSync()
    + +

    References XSyncPoint::isComplete, XSyncPoint::lock, smaxSync(), and XSyncPoint::status.

    + +
    +
    +
    +
    + + + + diff --git a/apidoc/html/smax-queue_8c.js b/apidoc/html/smax-queue_8c.js new file mode 100644 index 0000000..26cd229 --- /dev/null +++ b/apidoc/html/smax-queue_8c.js @@ -0,0 +1,10 @@ +var smax_queue_8c = +[ + [ "smaxCreateSyncPoint", "smax-queue_8c.html#a30e2e1eb462ed2274a55016830b9abc1", null ], + [ "smaxDestroySyncPoint", "smax-queue_8c.html#a012860edbebf45f24b1b08c02a37847b", null ], + [ "smaxQueue", "smax-queue_8c.html#a2c71427a215e2253d93de24788db338d", null ], + [ "smaxQueueCallback", "smax-queue_8c.html#a06781e13ee30b0530ba3ed2e4436b449", null ], + [ "smaxSetMaxPendingPulls", "smax-queue_8c.html#a7b7ff182bf54594d796d52e7d6a1a41d", null ], + [ "smaxSync", "smax-queue_8c.html#a90a901b9e649c77d29379b8fc31cbefc", null ], + [ "smaxWaitQueueComplete", "smax-queue_8c.html#a065361085eed93188b7fd3ffe3a7eaf5", null ] +]; \ No newline at end of file diff --git a/apidoc/html/smax-resilient_8c.html b/apidoc/html/smax-resilient_8c.html new file mode 100644 index 0000000..47fadde --- /dev/null +++ b/apidoc/html/smax-resilient_8c.html @@ -0,0 +1,212 @@ + + + + + + + +smax-clib: src/smax-resilient.c File Reference + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + +
    +
    smax-clib v0.9 +
    +
    A C/C++ client library for SMA-X
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    + +
    smax-resilient.c File Reference
    +
    +
    + +

    This module adds trusty push delivery to SMA-X. If the server cannot be reached, push requests are stored and updated locally until the server connection is restored, at which point they are delivered. +More...

    + + + + + + + + +

    +Functions

    boolean smaxIsResilient ()
     
    void smaxSetResilient (boolean value)
     
    void smaxSetResilientExit (boolean value)
     
    +

    Detailed Description

    +

    This module adds trusty push delivery to SMA-X. If the server cannot be reached, push requests are stored and updated locally until the server connection is restored, at which point they are delivered.

    +
    Date
    Aug 14, 2019
    +
    Author
    Attila Kovacs
    +

    This way, push requests are guaranteed to make it to the database sooner or later as long as the calling program keeps running.

    +

    It's mainly useful for daemons that generate infrequent data for the database. It's not especially meaningful for simple executables, which are run for limited time without persistence.

    +
    See also
    smaxSetResilient()
    +
    +smaxIsResilient()
    +

    Function Documentation

    + +

    ◆ smaxIsResilient()

    + +
    +
    + + + + + + + +
    boolean smaxIsResilient ()
    +
    +

    Checks whether the resiliency feature has been enabled.

    +
    Returns
    TRUE if enabled, otherwise FALSE.
    +
    See also
    smaxSetResilient()
    + +
    +
    + +

    ◆ smaxSetResilient()

    + +
    +
    + + + + + + + +
    void smaxSetResilient (boolean value)
    +
    +

    Enables the resiliency feature of the library, which keeps track of local changes destined to the database when the database is not reachable, and sending all locally stored updates once the database comes online again. However, after sending all pending updates to the remote server, the program may exit (default behavior), unless smaxSetResilientExit() is set to FALSE (0), so that it can be restarted in a fresh state, setting up subscriptions and scripts again as necessary.

    +
    Parameters
    + + +
    valueTRUE (non-zero) to enable, or FALSE (0) to disable resiliency.
    +
    +
    +
    See also
    smaxIsResilient()
    +
    +smaxSetResilientExit()
    + +

    References smaxAddConnectHook(), and smaxRemoveConnectHook().

    + +
    +
    + +

    ◆ smaxSetResilientExit()

    + +
    +
    + + + + + + + +
    void smaxSetResilientExit (boolean value)
    +
    +

    Sets whether the program should exit in resilient mode, after having pushed all local updates. The default is to exit since the reconnecting in resilient mode does not by itself re-establish existing subscriptions. However, when subscriptions aren't used, or if they are set up as a connect hook, the user may want the program to simply continue. This is possible by passing FALSE (0) as the argument to this call. This setting only takes effect when resilient mode is enabled. Otherwise, the exit policy is set by the RedisX library.

    +
    Parameters
    + + +
    valueWhether to exit the program after all local updates have been pushed to SMA-X after a recovering from an outage.
    +
    +
    +
    See also
    smaxSetResilient()
    +
    +smaxAddConnectHook()
    + +
    +
    +
    +
    + + + + diff --git a/apidoc/html/smax-resilient_8c.js b/apidoc/html/smax-resilient_8c.js new file mode 100644 index 0000000..00f8ee6 --- /dev/null +++ b/apidoc/html/smax-resilient_8c.js @@ -0,0 +1,6 @@ +var smax_resilient_8c = +[ + [ "smaxIsResilient", "smax-resilient_8c.html#a5f5e00f0fd063ac8e36827c852131358", null ], + [ "smaxSetResilient", "smax-resilient_8c.html#a469095a9a74a8ce5d6bbae347d7194e5", null ], + [ "smaxSetResilientExit", "smax-resilient_8c.html#ae638a5b4c82119eea5ef7a0ba2cd40c1", null ] +]; \ No newline at end of file diff --git a/apidoc/html/smax-util_8c.html b/apidoc/html/smax-util_8c.html new file mode 100644 index 0000000..4941f0d --- /dev/null +++ b/apidoc/html/smax-util_8c.html @@ -0,0 +1,1024 @@ + + + + + + + +smax-clib: src/smax-util.c File Reference + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + +
    +
    smax-clib v0.9 +
    +
    A C/C++ client library for SMA-X
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    + +
    smax-util.c File Reference
    +
    +
    + +

    A collection of commonly used functions for the SMA-X library. +More...

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    +Functions

    int smax2xField (XField *f)
     
    int smax2xStruct (XStructure *s)
     
    XField * smaxCreateField (const char *name, XType type, int ndim, const int *sizes, const void *value)
     
    XMetasmaxCreateMeta ()
     
    int smaxDeletePattern (const char *pattern)
     
    int smaxError (const char *func, int errorCode)
     
    const char * smaxErrorDescription (int code)
     
    int smaxGetMetaCount (const XMeta *m)
     
    char * smaxGetScriptSHA1 (const char *scriptName, int *status)
     
    int smaxGetServerTime (struct timespec *t)
     
    double smaxGetTime (const char *timestamp)
     
    int smaxParseTime (const char *timestamp, time_t *secs, long *nanosecs)
     
    void smaxResetMeta (XMeta *m)
     
    int smaxScriptError (const char *name, int status)
     
    int smaxScriptErrorAsync (const char *name, int status)
     
    void smaxSetOrigin (XMeta *m, const char *origin)
     
    int smaxStringToValues (const char *str, void *value, XType type, int eCount, int *pos)
     
    char * smaxStringType (XType type)
     
    int smaxTimestamp (char *buf)
     
    __inline__ int smaxTimeToString (const struct timespec *time, char *buf)
     *‍/
     
    void smaxTransmitErrorHandler (Redis *redis, enum redisx_channel channel, const char *op)
     
    XType smaxTypeForString (const char *type)
     
    int smaxUnpackStrings (const char *data, int len, int count, char **dst)
     
    char * smaxValuesToString (const void *value, XType type, int eCount, char *trybuf, int trylength)
     
    int x2smaxField (XField *f)
     
    int x2smaxStruct (XStructure *s)
     
    +

    Detailed Description

    +

    A collection of commonly used functions for the SMA-X library.

    +
    Date
    Jun 25, 2019
    +
    Author
    Attila Kovacs
    +

    Function Documentation

    + +

    ◆ smax2xField()

    + +
    +
    + + + + + + + +
    int smax2xField (XField * f)
    +
    +

    Converts SMA-X field with serialized string value storage to a standard xchange field with a native value storage.

    +
    Parameters
    + + +
    fPointer to field to convert
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NULL if the input field or the deserialized value is NULL, X_TYPE_INVALID if the field is of a type that cannot be deserialized, or else an error code returned by smaxStringToValues().
    +
    See also
    x2smaxField()
    +
    +smax2xStruct()
    + +

    References smax2xStruct(), and smaxStringToValues().

    + +
    +
    + +

    ◆ smax2xStruct()

    + +
    +
    + + + + + + + +
    int smax2xStruct (XStructure * s)
    +
    +

    Converts an SMA-X structure with serialized string value storage to a standard xchange structure with a native value storage.

    +
    Parameters
    + + +
    sPointer to structure to convert
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_STRUCT_INVALID if the structure is NULL, or had a NULL substructure, or else an error code returned by smax2xField().
    +
    See also
    x2smaxStruct()
    +
    +smax2xField()
    + +

    References smax2xField().

    + +
    +
    + +

    ◆ smaxCreateField()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    XField * smaxCreateField (const char * name,
    XType type,
    int ndim,
    const int * sizes,
    const void * value )
    +
    +

    Creates a generic field of a given name and type and dimensions using the specified native values. It is like xCreateField() except that the field is created in serialized form for SMA-X.

    +
    Parameters
    + + + + + + +
    nameField name
    typeStorage type, e.g. X_INT.
    ndimNumber of dimensionas (1:20). If ndim < 1, it will be reinterpreted as ndim=1, size[0]=1;
    sizesArray of sizes along each dimensions, with at least ndim elements, or NULL with ndim<1.
    valuePointer to the native data location in memory. Unless it is of type X_STRUCT, the data stored in the field is a copy (for type X_RAW) or serialized string (otherwise).
    +
    +
    +
    Returns
    A newly created field with the supplied data, or NULL if there was an error.
    +
    See also
    xSetField()
    + +

    References smaxValuesToString().

    + +
    +
    + +

    ◆ smaxCreateMeta()

    + +
    +
    + + + + + + + +
    XMeta * smaxCreateMeta ()
    +
    +

    Creates a new SMA-X metadata object with defaults. Effectively the same as calling calloc() followed by xResetMeta().

    +
    Returns
    Pointer to a new metadata object initialized to defaults.
    +
    See also
    X_META_INIT
    + +

    References smaxResetMeta().

    + +
    +
    + +

    ◆ smaxDeletePattern()

    + +
    +
    + + + + + + + +
    int smaxDeletePattern (const char * pattern)
    +
    +

    Deletes variables and metadata from SMA-X.

    +
    Parameters
    + + +
    patternGlob variable name pattern
    +
    +
    +
    Returns
    The number of variables deleted from the SQL DB
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxError()

    + +
    +
    + + + + + + + + + + + +
    int smaxError (const char * func,
    int errorCode )
    +
    +

    Prints a descriptive error message to stderr, and returns the error code.

    +
    Parameters
    + + + +
    funcString that describes the function or location where the error occurred.
    errorCodeError code that describes the failure.
    +
    +
    +
    Returns
    Same error code as specified on input.
    + +

    References smaxErrorDescription().

    + +
    +
    + +

    ◆ smaxErrorDescription()

    + +
    +
    + + + + + + + +
    const char * smaxErrorDescription (int code)
    +
    +

    Returns a string description for one of the RM error codes.

    +
    Parameters
    + + +
    codeOne of the error codes defined in 'xchange.h' or in 'smax.h' (e.g. X_NO_PIPELINE)
    +
    +
    + +
    +
    + +

    ◆ smaxGetMetaCount()

    + +
    +
    + + + + + + + +
    int smaxGetMetaCount (const XMeta * m)
    +
    +

    Returns the number of elements stored from a metadata.

    +
    Parameters
    + + +
    mpointer to metadata that defines the dimension and shape of elements.
    +
    +
    +
    Returns
    the total number of elements represented by the metadata
    + +

    References XMeta::storeDim, and XMeta::storeSizes.

    + +
    +
    + +

    ◆ smaxGetScriptSHA1()

    + +
    +
    + + + + + + + + + + + +
    char * smaxGetScriptSHA1 (const char * scriptName,
    int * status )
    +
    +

    Gets the SHA1 script ID for the currently loaded script with the specified name.

    +
    Parameters
    + + + +
    scriptNameCase-sensitive name of the script, e.g. "GetStruct".
    statusPointer int which to return status, which is X_SUCCESS if the SHA1 id was successfully obtained, or else an appropriate error code.
    +
    +
    +
    Returns
    String buffer with the SHA1 key or NULL if it could not be retrieved. (The caller is responsible freeing the buffer after use.)
    + +

    References SMAX_SCRIPTS, and smaxGetRedis().

    + +
    +
    + +

    ◆ smaxGetServerTime()

    + +
    +
    + + + + + + + +
    int smaxGetServerTime (struct timespec * t)
    +
    +

    Returns the current time on the Redis server instance.

    +
    Parameters
    + + +
    tPointer to a timespec structure in which to return the server time.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NO_INIT if not connected to SMA-X, or X_NULL if either argument is NULL, or X_PARSE_ERROR if could not parse the response, or another error returned by redisxCheckRESP().
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxGetTime()

    + +
    +
    + + + + + + + +
    double smaxGetTime (const char * timestamp)
    +
    +

    Returns the a sub-second precision UNIX time value for the given SMA-X timestamp

    +
    Parameters
    + + +
    timestampThe string timestamp returned by SMA-X
    +
    +
    +
    Returns
    Corresponding UNIX time with sub-second precision, or NAN if the input could not be parsed.
    + +

    References smaxParseTime().

    + +
    +
    + +

    ◆ smaxParseTime()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxParseTime (const char * timestamp,
    time_t * secs,
    long * nanosecs )
    +
    +

    Parses a timestamp into broken-down UNIX time.

    +
    Parameters
    + + + + +
    [in]timestampTimestamp string as returned in redis queries;
    [out]secsPointer to the returned UNIX time (seconds).
    [out]nanosecsPointer to the retuned sub-second remainder as nanoseconds, or NULL if nor requested.
    +
    +
    +
    Returns
    X_SUCCESS(0) if the timestamp was successfully parsed. X_NULL if there was no timestamp (empty or invalid string), or the secs argument is NULL. X_PARSE_ERROR if the seconds could not be parsed. 1 if there was an error parsing the nanosec part. X_NULL if the secs arhument is NULL
    + +
    +
    + +

    ◆ smaxResetMeta()

    + +
    +
    + + + + + + + +
    void smaxResetMeta (XMeta * m)
    +
    +

    Set metadata to their default values. After resetting the supplied metadata will have exactly the same content as if it were initialized with the X_META_INIT macro.

    +
    Parameters
    + + +
    mPointer to the metadata that is to be cleared.
    +
    +
    +
    See also
    X_META_INIT
    + +

    References X_META_INIT.

    + +
    +
    + +

    ◆ smaxScriptError()

    + +
    +
    + + + + + + + + + + + +
    int smaxScriptError (const char * name,
    int status )
    +
    +

    SMA-X error handler for when the LUA scripts do not execute. It prints a message to stderr, then depending on whether SMA-X is in resilient mode, it will try to reconnect to SMA-X in the background, or else exits the program with X_NO_SERVICE. You must not call this function with a locked config mutex (via smaxConfigLock()). Instead use the async version of this function after smaxConfigLock().

    +
    Parameters
    + + + +
    nameThe name of the calling function or name of script (whichever is more informative).
    statusAn approprioate error code from xchange.h to indicate the type of error.
    +
    +
    +
    See also
    smaxScriptErrorAsync()
    +
    +smaxSetResilient()
    + +

    References smaxScriptErrorAsync().

    + +
    +
    + +

    ◆ smaxScriptErrorAsync()

    + +
    +
    + + + + + + + + + + + +
    int smaxScriptErrorAsync (const char * name,
    int status )
    +
    +

    Same as smaxScriptError(), but can be used after smaxConfigLock().

    +
    Parameters
    + + + +
    nameThe name of the calling function or name of script (whichever is more informative).
    statusAn approprioate error code from xchange.h to indicate the type of error.
    +
    +
    +
    See also
    smaxScriptError()
    +
    +smaxSetResilient()
    + +

    References smaxErrorDescription(), smaxIsConnected(), and smaxIsResilient().

    + +
    +
    + +

    ◆ smaxSetOrigin()

    + +
    +
    + + + + + + + + + + + +
    void smaxSetOrigin (XMeta * m,
    const char * origin )
    +
    +

    Sets the 'origin' field of an SMA-X metadata to the specified value, truncating as necessary to fit into the allotted fixed storage.

    +
    Parameters
    + + + +
    originThe origination information, usually as hostname:progname
    mPointer to metadata to set.
    +
    +
    + +

    References XMeta::origin, and SMAX_ORIGIN_LENGTH.

    + +
    +
    + +

    ◆ smaxStringToValues()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    int smaxStringToValues (const char * str,
    void * value,
    XType type,
    int eCount,
    int * pos )
    +
    +

    Deserializes a string to binary values.

    +
    Parameters
    + + + + + + +
    [in]strSerialized ASCII representation of the data (as stored by Redis).
    [out]valuePointer to the buffer that will hold the binary values. The caller is responsible for ensuring the buffer is sufficiently sized for holding the data for the given variable.
    [in]typeShare type, e.g. X_INT. The types X_RAW, X_STRUCT are not supported by this function.
    [in]eCountNumber of elements to retrieve. Ignored for X_STRUCT.
    [out]posParse position, i.e. the number of characters parsed from the input string...
    +
    +
    +
    Returns
    Number of elements successfully parsed, or a negative error code:
                            X_NULL               If the value or str argument is NULL.
    +                        X_TYPE_INVALID       If the type is not supported.
    +                        X_SIZE_INVALID       If size is invalid (e.g. X_RAW, X_STRUCT)
    +                        X_PARSE_ERROR        If the tokens could not be parsed in the format expected
    +
    + +

    References smaxUnpackStrings().

    + +
    +
    + +

    ◆ smaxStringType()

    + +
    +
    + + + + + + + +
    char * smaxStringType (XType type)
    +
    +

    Returns the string type for a given XType argument as a constant expression. For examples X_LONG -> "int64".

    +
    Parameters
    + + +
    typeSMA-X type, e.g. X_FLOAT
    +
    +
    +
    Returns
    Corresponding string type, e.g. "float". (Default is "string" – since typically anything can be represented as strings.)
    +
    See also
    smaxTypeForString()
    + +
    +
    + +

    ◆ smaxTimestamp()

    + +
    +
    + + + + + + + +
    int smaxTimestamp (char * buf)
    +
    +

    Prints the current time into the supplied buffer with subsecond precision.

    +
    Parameters
    + + +
    [out]bufPointer to string buffer, must be at least X_TIMESTAMP_LENGTH in size.
    +
    +
    +
    Returns
    Number of characters printed, not including the terminating '\0', or else an error code (<0) if the buf argument is NULL.
    + +

    References smaxTimeToString().

    + +
    +
    + +

    ◆ smaxTimeToString()

    + +
    +
    + + + + + + + + + + + +
    __inline__ int smaxTimeToString (const struct timespec * time,
    char * buf )
    +
    + +

    *‍/

    +

    Prints the given UNIX time into the supplied buffer with subsecond precision.

    +
    Parameters
    + + + +
    [in]timePointer to time value.
    [out]bufPointer to string buffer, must be at least X_TIMESTAMP_LENGTH in size.
    +
    +
    +
    Returns
    Number of characters printed, not including the terminating '\0', or else an error code (<0) if the buf argument is NULL.
    + +
    +
    + +

    ◆ smaxTransmitErrorHandler()

    + +
    +
    + + + + + + + + + + + + + + + + +
    void smaxTransmitErrorHandler (Redis * redis,
    enum redisx_channel channel,
    const char * op )
    +
    +

    The SMA-X error handler for Redis transmit (send or receive) errors. It prints a message to stderr, then depending on whether SMA-X is in resilient mode, it will try to reconnect to SMA-X in the background, or else exits the program with X_NO_SERVICE.

    +
    Parameters
    + + + + +
    redisThe Redis instance in which the error occurred. In case of SMA-X this will always be the Redis instance used by SMA-X.
    channelThe Redis channel index on which the error occured, such as REDIS_INTERAVTIVE_CHANNEL
    opThe operation during which the error occurred, e.g. 'send' or 'read'.
    +
    +
    +
    See also
    smaxSetResilient()
    +
    +redisxSetTrasmitErrorHandler()
    + +

    References smaxGetRedis(), and smaxIsResilient().

    + +
    +
    + +

    ◆ smaxTypeForString()

    + +
    +
    + + + + + + + +
    XType smaxTypeForString (const char * type)
    +
    +

    Returns the XType for a given case-sensitive type string. For example "float" -> X_FLOAT. The value "raw" will return X_RAW.

    +
    Parameters
    + + +
    typeString type, e.g. "struct".
    +
    +
    +
    Returns
    Corresponding XType, e.g. X_STRUCT. (The default return value is X_RAW, since all Redis values can be represented as raw strings.)
    +
    See also
    smaxStringType()
    + +
    +
    + +

    ◆ smaxUnpackStrings()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxUnpackStrings (const char * data,
    int len,
    int count,
    char ** dst )
    +
    +

    Returns an array of dynamically allocated strings from a packed buffer of consecutive 0-terminated or '\r'-separated string elements.

    +
    Parameters
    + + + + + +
    [in]dataPointer to the packed string data buffer.
    [in]lenlength of packed string (excl. termination).
    [in]countNumber of string elements expected. If fewer than that are found in the packed data, then the returned array of pointers will be padded with NULL.
    [out]dstAn array of string pointers (of size 'count') which will point to dynamically allocated string (char*) elements. The array is assumed to be uninitialized, and elements will be allocated as necessary.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NULL if one of the argument pointers is NULL, or else X_INCOMPLETE if some of the components were too large to unpack (alloc error).
    + +
    +
    + +

    ◆ smaxValuesToString()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    char * smaxValuesToString (const void * value,
    XType type,
    int eCount,
    char * trybuf,
    int trylength )
    +
    +

    Serializes binary values into a string representation (for Redis).

    +
    Parameters
    + + + + + + +
    [in]valuePointer to an array of values, or NULL to produce all zeroes. If type is X_STRING value should be a pointer to a char** (array of string pointers), as opposed to X_CHAR(n), which expects a contiguous char* buffer with [n * eCount] length (Note, a char[eCount][n] is equivalent to such a char* buffer).
    [in]typeShare type, e.g. X_DOUBLE. All type except X_STRUCT are supported.
    [in]eCountNumber of elements (ignored for X_RAW).
    [in,out]trybuf(optional) An optional pointer to a buffer that will be used if sufficient (can be NULL).
    [in]trylength(optional) Size of the optional buffer.
    +
    +
    +
    Returns
    The pointer to the string buffer holding the ASCII values. It may be the supplied buffer (if sufficient), the input value (if type is X_RAW) or else a dynamically allocated buffer, or NULL if the key is malformed. If the returned value is neither the input value nor trybuf, then the caller is responsible for calling free() on the dynamically allocated buffer after use.
    + +
    +
    + +

    ◆ x2smaxField()

    + +
    +
    + + + + + + + +
    int x2smaxField (XField * f)
    +
    +

    Converts a standard xchange field (with a native value storage) to an SMA-X field with serialized string value storage.

    +
    Parameters
    + + +
    [in,out]fPointer to field to convert
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NULL if the input field or the serialized value is NULL.
    +
    See also
    smax2xField()
    +
    +x2smaxStruct()
    + +

    References smaxValuesToString(), and x2smaxStruct().

    + +
    +
    + +

    ◆ x2smaxStruct()

    + +
    +
    + + + + + + + +
    int x2smaxStruct (XStructure * s)
    +
    +

    Converts a standard xchange structure (with a native value storage) to an SMA-X structure with serialized string value storage.

    +
    Parameters
    + + +
    sPointer to structure to convert
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_STRUCT_INVALID if the structure is NULL, or had a NULL substructure. X_NULL if there was a field that could not be converted.
    +
    See also
    smax2xStruct()
    +
    +x2smaxField()
    + +

    References x2smaxField().

    + +
    +
    +
    +
    + + + + diff --git a/apidoc/html/smax-util_8c.js b/apidoc/html/smax-util_8c.js new file mode 100644 index 0000000..aa8c445 --- /dev/null +++ b/apidoc/html/smax-util_8c.js @@ -0,0 +1,29 @@ +var smax_util_8c = +[ + [ "smax2xField", "smax-util_8c.html#abfe751f22aa718133911ffdee848f64a", null ], + [ "smax2xStruct", "smax-util_8c.html#a50fef3b0daf40f7de6f52b05abd2963c", null ], + [ "smaxCreateField", "smax-util_8c.html#a9871356984c4794a9f9caa3870dc6794", null ], + [ "smaxCreateMeta", "smax-util_8c.html#a48decaf10195b2f21fa77d8ea9b94fff", null ], + [ "smaxDeletePattern", "smax-util_8c.html#a6c116311d61874554f98332831ad872b", null ], + [ "smaxError", "smax-util_8c.html#aefcb16af3690ffe9c77224af6b394869", null ], + [ "smaxErrorDescription", "smax-util_8c.html#a51856e0dc0261f8e44c8635d31d6193c", null ], + [ "smaxGetMetaCount", "smax-util_8c.html#ac6d47a508669e4ee215cb72c5366fc52", null ], + [ "smaxGetScriptSHA1", "smax-util_8c.html#a8ef420555c1ddbbcd9f4213f65b4ca66", null ], + [ "smaxGetServerTime", "smax-util_8c.html#ae6941b762acbd37c60b012d4157681a8", null ], + [ "smaxGetTime", "smax-util_8c.html#a2a71d93de952060be0154dd5f0d78496", null ], + [ "smaxParseTime", "smax-util_8c.html#a2c3c82ba5e7844e9f1b70fb4d51716ef", null ], + [ "smaxResetMeta", "smax-util_8c.html#a7ea3483859bf8f7764143b8590af067e", null ], + [ "smaxScriptError", "smax-util_8c.html#a3385ed559f3866d76ec4efaa2885daa4", null ], + [ "smaxScriptErrorAsync", "smax-util_8c.html#af3acc2100069feec3a52475cdb24d479", null ], + [ "smaxSetOrigin", "smax-util_8c.html#a9802443ba0d569c3614f5dcf8b0cfc4b", null ], + [ "smaxStringToValues", "smax-util_8c.html#a9e3c024a1db97e7adc8a40694c657fd1", null ], + [ "smaxStringType", "smax-util_8c.html#a8d9d92ad8825d4adad4d6288a5681351", null ], + [ "smaxTimestamp", "smax-util_8c.html#ae56da599747b207813a710efc07dd47d", null ], + [ "smaxTimeToString", "smax-util_8c.html#a1c29c7229e7006aea4fc3eb6d4b4ee0e", null ], + [ "smaxTransmitErrorHandler", "smax-util_8c.html#a164a9c0f870cf0a1fa4f7e66f25452e5", null ], + [ "smaxTypeForString", "smax-util_8c.html#af6a70e896526629e2130009882a1bff8", null ], + [ "smaxUnpackStrings", "smax-util_8c.html#a5665cd4f5087ab7a07239c30bc561173", null ], + [ "smaxValuesToString", "smax-util_8c.html#a4a80ebd309352379d3691f264282d96b", null ], + [ "x2smaxField", "smax-util_8c.html#a76bd110891905fe4bdae6628547c50d1", null ], + [ "x2smaxStruct", "smax-util_8c.html#a65cc6cdad09f861b968e2d492abed977", null ] +]; \ No newline at end of file diff --git a/apidoc/html/smax_8c.html b/apidoc/html/smax_8c.html new file mode 100644 index 0000000..6ea8ee1 --- /dev/null +++ b/apidoc/html/smax_8c.html @@ -0,0 +1,1348 @@ + + + + + + + +smax-clib: src/smax.c File Reference + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + +
    +
    smax-clib v0.9 +
    +
    A C/C++ client library for SMA-X
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    + +
    smax.c File Reference
    +
    +
    + +

    SMA-X is a software implementation for SMA shared data, and is the base layer for the software reflective memory (RM) emulation, and DSM replacement. It works by communicating TCP/IP messages to a central Redis server. +More...

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    +Functions

    int smaxAddConnectHook (void(*setupCall)(void))
     
    int smaxAddDisconnectHook (void(*cleanupCall)(void))
     
    int smaxAddSubscriber (const char *idStem, RedisSubscriberCall f)
     
    int smaxConnect ()
     
    int smaxConnectTo (const char *server)
     
    int smaxDisconnect ()
     
    char * smaxGetHostName ()
     
    char ** smaxGetKeys (const char *table, int *n)
     
    char * smaxGetProgramID ()
     
    Redis * smaxGetRedis ()
     
    int smaxIsConnected ()
     
    boolean smaxIsPipelined ()
     
    boolean smaxIsVerbose ()
     
    int smaxKeyCount (const char *table)
     
    int smaxPull (const char *table, const char *key, XType type, int count, void *value, XMeta *meta)
     
    int smaxReconnect ()
     
    int smaxReleaseWaits ()
     
    int smaxRemoveConnectHook (void(*setupCall)(void))
     
    int smaxRemoveDisconnectHook (void(*cleanupCall)(void))
     
    int smaxRemoveSubscribers (RedisSubscriberCall f)
     
    int smaxSetAuth (const char *username, const char *password)
     
    int smaxSetDB (int idx)
     
    void smaxSetHostName (const char *name)
     
    int smaxSetPipelineConsumer (void(*f)(RESP *))
     
    int smaxSetPipelined (boolean isEnabled)
     
    int smaxSetServer (const char *host, int port)
     
    int smaxSetTcpBuf (int size)
     
    void smaxSetVerbose (boolean value)
     
    int smaxShare (const char *table, const char *key, const void *value, XType type, int count)
     
    int smaxShareArray (const char *table, const char *key, const void *ptr, XType type, int ndim, const int *sizes)
     
    int smaxShareField (const char *table, const XField *f)
     
    int smaxShareStruct (const char *id, const XStructure *s)
     
    int smaxSubscribe (const char *table, const char *key)
     
    int smaxUnsubscribe (const char *table, const char *key)
     
    int smaxWaitOnAnySubscribed (char **changedTable, char **changedKey, int timeout)
     
    + + + + + + + + + + + + + +

    +Variables

    +char * GET_STRUCT
     SHA1 key for calling HGetStruct LUA script.
     
    +char * HGET_WITH_META
     SHA1 key for calling HGetWithMeta LUA script.
     
    +char * HMSET_WITH_META
     SHA1 key for calling HMSetWithMeta LUA script.
     
    +char * HSET_WITH_META
     SHA1 key for calling HSetWithMeta LUA script.
     
    +

    Detailed Description

    +

    SMA-X is a software implementation for SMA shared data, and is the base layer for the software reflective memory (RM) emulation, and DSM replacement. It works by communicating TCP/IP messages to a central Redis server.

    +
    Date
    Jan 26, 2018
    +
    Author
    Attila Kovacs
    +

    There is also extra functionality, for configuring, performance tweaking, verbosity control, and some convenience methods (e.g. data serialization/deserialization).

    +

    Function Documentation

    + +

    ◆ smaxAddConnectHook()

    + +
    +
    + + + + + + + +
    int smaxAddConnectHook (void(*)(void) setupCall)
    +
    +

    Add a callback function for when SMA-X is connected. It's a wrapper to redisxAddConnectHook().

    +
    Parameters
    + + +
    setupCallCallback function
    +
    +
    +
    Returns
    X_SUCCESS (0) or an error code (<0) from redisxAddConnectHook().
    +
    See also
    smaxRemoveConnectHook()
    +
    +smaxConnect()
    +
    +smaxConnectTo()
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxAddDisconnectHook()

    + +
    +
    + + + + + + + +
    int smaxAddDisconnectHook (void(*)(void) cleanupCall)
    +
    +

    Add a callback function for when SMA-X is disconnected. It's a wrapper to redisxAddDisconnectHook().

    +
    Parameters
    + + +
    cleanupCallCallback function
    +
    +
    +
    Returns
    X_SUCCESS (0) or an error code (<0) from redisxAddConnectHook().
    +
    See also
    smaxRemoveDisconnectHook()
    +
    +smaxDisconnect()
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxAddSubscriber()

    + +
    +
    + + + + + + + + + + + +
    int smaxAddSubscriber (const char * idStem,
    RedisSubscriberCall f )
    +
    +

    Add a subcriber (callback) function to process incoming PUB/SUB messages for a given SMA-X table (or id). The function should itself check that the channel receiving notification is indeed what it expectes before acting on it, as the callback routine will be invoked for any update inside the specified table, unless the table argument refers to a specific aggregate ID of a single variable. This call only registers the callback routine for SMA-X update notifications for variables that begin with the specified stem. You will still have to subscrive to any relevant variables with smaxSubscribe() to enable delivering update notifications for the variables of your choice.

    +
    Parameters
    + + + +
    idStemTable name or ID stem for which the supplied callback function will be invoked as long as the beginning of the PUB/SUB update channel matches the given stem. Alternatively, it can be a fully qualified SMA-X ID (of the form table:key) f a single variable.
    fThe function to call when there is an incoming PUB/SUB update to a channel starting with stem.
    +
    +
    +
    Returns
    X_SUCCESS if successful, or else an approriate error code by redisxAddSubscriber()
    +
    See also
    smaxSubscribe()
    + +

    References SMAX_UPDATES_ROOT, and smaxGetRedis().

    + +
    +
    + +

    ◆ smaxConnect()

    + +
    +
    + + + + + + + +
    int smaxConnect ()
    +
    +

    Initializes the SMA-X sharing library in this runtime instance.

    +
    Returns
    X_SUCCESS If the library was successfully initialized X_ALREADY_OPEN If SMA-X sharing was already open. X_NO_SERVICE If the there was an issue establishing the necessary network connection(s). X_NAME_INVALID If the redis server name lookup failed. X_NULL If the Redis IP address is NULL
    +
    See also
    smaxSetServer()
    +
    +smaxSetAuth()
    +
    +smaxConnectTo()
    +
    +smaxDisconnect()
    +
    +smaxReconnect()
    +
    +smaxIsConnected()
    + +

    References SMAX_DEFAULT_HOSTNAME, smaxAddConnectHook(), smaxAddDisconnectHook(), smaxAddSubscriber(), smaxGetProgramID(), smaxIsConnected(), smaxLazyFlush(), smaxReleaseWaits(), smaxSetPipelineConsumer(), smaxSetResilient(), and smaxTransmitErrorHandler().

    + +
    +
    + +

    ◆ smaxConnectTo()

    + +
    +
    + + + + + + + +
    int smaxConnectTo (const char * server)
    +
    +

    Initializes the SMA-X sharing library in this runtime instance with the specified Redis server. SMA-X is initialized in resilient mode, so that we'll automatically attempt to reconnect to the Redis server if the connection is severed (once it was established). If that is not the desired behavior, you should call smaxSetResilient(FALSE) after connecting.

    +
    Parameters
    + + +
    serverSMA-X Redis server name or IP address, e.g. "127.0.0.1".
    +
    +
    +
    Returns
    X_SUCCESS If the library was successfully initialized X_NO_SERVICE If the there was an issue establishing the necessary network connection(s).
    +
    See also
    smaxConnect()
    +
    +smaxDisconnect()
    +
    +smaxReconnect()
    +
    +smaxIsConnected()
    +
    +smaxSetResilient()
    + +

    References smaxConnect(), and smaxSetServer().

    + +
    +
    + +

    ◆ smaxDisconnect()

    + +
    +
    + + + + + + + +
    int smaxDisconnect ()
    +
    +

    Disables the SMA-X sharing capability, closing underlying network connections.

    +
    Returns
    X_SUCCESS (0) if the sharing was properly ended. X_NO_INIT if SMA-X was has not been started prior to this call.
    +
    See also
    smaxConnect()
    +
    +smaxConnectTo()
    +
    +smaxReconnect()
    +
    +smaxIsConnected()
    + +

    References smaxIsConnected().

    + +
    +
    + +

    ◆ smaxGetHostName()

    + +
    +
    + + + + + + + +
    char * smaxGetHostName ()
    +
    +

    Returns the host name on which this program is running. It returns a reference to the same static variable every time. As such you should never call free() on the returned value. Note, that only the leading part of the host name is returned, so for a host that is registered as 'somenode.somedomain' only 'somenode' is returned.

    +
    Returns
    The host name string (leading part only).
    +
    See also
    smaxSetHostName()
    + +
    +
    + +

    ◆ smaxGetKeys()

    + +
    +
    + + + + + + + + + + + +
    char ** smaxGetKeys (const char * table,
    int * n )
    +
    +

    Returns a snapshot of the key names stored in a given Redis hash table, ot NULL if there was an error.

    +
    Parameters
    + + + +
    tableHost name or owner ID whose variable to count.
    [out]nPointer to which the number of keys (>=0) or an error (<0) is returned. An error returned by redisxGetKeys(), or else:
    +
    +
    +

    X_NO_INIT if the SMA-X sharing was not initialized, e.g. via smaxConnect(). X_GROUP_INVALID if the table name is invalid. X_NULL if the output 'n' pointer is NULL.

    +
    Returns
    An array of pointers to the names of Redis keys.
    +
    See also
    smaxKeyCount()
    + +
    +
    + +

    ◆ smaxGetProgramID()

    + +
    +
    + + + + + + + +
    char * smaxGetProgramID ()
    +
    +

    Returns the SMA-X program ID.

    +
    Returns
    The SMA-X program ID as <hostname>:<programname>, e.g. "hal9000:statusServer".
    + +

    References smaxGetHostName().

    + +
    +
    + +

    ◆ smaxGetRedis()

    + +
    +
    + + + + + + + +
    Redis * smaxGetRedis ()
    +
    +

    Returns the Redis connection information for SMA-X

    +
    Returns
    The structure containing the Redis connection data.
    +
    See also
    smaxConnect()
    +
    +smaxConnectTo()
    +
    +smaxIsConnected()
    + +
    +
    + +

    ◆ smaxIsConnected()

    + +
    +
    + + + + + + + +
    int smaxIsConnected ()
    +
    +

    Checks whether SMA-X sharing is currently open (by a preceding call to smaxConnect() call.

    +
    See also
    smaxConnect()
    +
    +smaxConnectTo()
    +
    +smaxDisconnect()
    +
    +smaxReconnect()
    + +
    +
    + +

    ◆ smaxIsPipelined()

    + +
    +
    + + + + + + + +
    boolean smaxIsPipelined ()
    +
    +

    Check if SMA-X is configured with pipeline mode enabled.

    +
    Returns
    TRUE (1) if the pipeline is enabled, or else FALSE (0)
    +
    See also
    smaxSetPipelined()
    + +
    +
    + +

    ◆ smaxIsVerbose()

    + +
    +
    + + + + + + + +
    boolean smaxIsVerbose ()
    +
    +

    Checks id verbose reporting is enabled.

    +
    Returns
    TRUE if verbose reporting is enabled, otherwise FALSE.
    +
    See also
    smaxSetVerbose()
    + +
    +
    + +

    ◆ smaxKeyCount()

    + +
    +
    + + + + + + + +
    int smaxKeyCount (const char * table)
    +
    +

    Retrieve the current number of variables stored on host (or owner ID).

    +
    Parameters
    + + +
    tableHash table name.
    +
    +
    +
    Returns
    The number of keys (fields) in the specified table (>= 0), or an error code (<0), such as: X_NO_INIT if the SMA-X sharing was not initialized, e.g. via smaConnect(). X_GROUP_INVALID if the table name is invalid. or one of the errors (<0) returned by redisxRequest().
    +
    See also
    smaxGetKeys()
    + +
    +
    + +

    ◆ smaxPull()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    int smaxPull (const char * table,
    const char * key,
    XType type,
    int count,
    void * value,
    XMeta * meta )
    +
    +

    Pull data from the specified hash table. This calls data via the interactive client to Redis.

    +
    Parameters
    + + + + + + + +
    [in]tableHash table name.
    [in]keyVariable name under which the data is stored.
    [in]typeSMA-X variable type, e.g. X_FLOAT or X_CHARS(40), of the buffer.
    [in]countNumber of points to retrieve into the buffer.
    [out]valuePointer to the buffer to which the data is to be retrieved.
    [out]metaPointer to metadata or NULL if no metadata is needed.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized. X_GROUP_INVALID if the 'table' argument is invalid. X_NAME_INVALID if the 'key' argument is invalid. X_NULL if an essential argument is NULL or contains NULL. X_NO_SERVICE if there was no connection to the Redis server. X_FAILURE if there was an underlying failure.
    +
    See also
    smaxLazyPull()
    +
    +smaxQueue()
    + +
    +
    + +

    ◆ smaxReconnect()

    + +
    +
    + + + + + + + +
    int smaxReconnect ()
    +
    +

    Reconnects to the SMA-X server. It will try connecting repeatedly at regular intervals until the connection is made. If resilient mode is enabled, then locally accumulated shares will be sent to the Redis server upon reconnection. However, subscriptions are not automatically re-established. The caller is responsible for reinstate any necessary subscriptions after the reconnection or via an approproate connection hook.

    +
    Returns
    X_SUCCESS (0) if successful X_NO_INIT if SMA-X was never initialized.
    +

    or the error returned by redisxReconnect().

    +
    See also
    smaxConnect()
    +
    +smaxConnectTo()
    +
    +smaxDisconnect()
    +
    +smaxIsConnected()
    +
    +smaxSetResilient()
    +
    +smaxAddConnectHook()
    + +

    References SMAX_RECONNECT_RETRY_SECONDS.

    + +
    +
    + +

    ◆ smaxReleaseWaits()

    + +
    +
    + + + + + + + +
    int smaxReleaseWaits ()
    +
    +

    Unblocks all smax_wait*() calls, which will return X_REL_PREMATURE, as a result.

    +
    Returns
    X_SUCCESS (0)
    +
    See also
    smaxWaitOnAnySubscribed()
    + +

    References RELEASEID.

    + +
    +
    + +

    ◆ smaxRemoveConnectHook()

    + +
    +
    + + + + + + + +
    int smaxRemoveConnectHook (void(*)(void) setupCall)
    +
    +

    Remove a post-connection callback function. It's a wrapper to redisxRemoveConnectHook().

    +
    Parameters
    + + +
    setupCallCallback function
    +
    +
    +
    Returns
    X_SUCCESS (0) or an error code (<0) from redisxAddConnectHook().
    +
    See also
    smaxAddConnectHook()
    +
    +smaxConnect()
    +
    +smaxConnectTo()
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxRemoveDisconnectHook()

    + +
    +
    + + + + + + + +
    int smaxRemoveDisconnectHook (void(*)(void) cleanupCall)
    +
    +

    Remove a post-cdisconnect callback function. It's a wrapper to redisxRemiveDisconnectHook().

    +
    Parameters
    + + +
    cleanupCallCallback function
    +
    +
    +
    Returns
    X_SUCCESS (0) or an error code (<0) from redisxAddConnectHook().
    +
    See also
    smaxAddDisconnectHook()
    +
    +smaxDisconnect()
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxRemoveSubscribers()

    + +
    +
    + + + + + + + +
    int smaxRemoveSubscribers (RedisSubscriberCall f)
    +
    +

    Remove all instances of a subscriber callback function from the current list of functions processing PUB/SUB messages. This call only deactivates the callback routine, but does not stop the delivery of update notifications from the Redis server. You should therefore also call smaxUnsubscribe() as appropriate to stop notifications for variables that no longer have associated callbacks.

    +
    Parameters
    + + +
    fFunction to remove
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or else an error (<0) returned by redisxRemoveSubscriber().
    +
    See also
    smaxUnsubscribe()
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxSetAuth()

    + +
    +
    + + + + + + + + + + + +
    int smaxSetAuth (const char * username,
    const char * password )
    +
    +

    Sets the SMA-X database authentication parameters (if any) before connecting to the SMA-X server.

    +
    Parameters
    + + + +
    usernameRedis ACL user name (if any), or NULL for no user-based authentication
    passwordRedis database password (if any), or NULL if the database is not password protected
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_ALREADY_OPEN if cannot alter the server configuration because we are already in a connected state.
    +
    See also
    smaxSetServer()
    +
    +smaxConnect()
    + +

    References smaxIsConnected().

    + +
    +
    + +

    ◆ smaxSetDB()

    + +
    +
    + + + + + + + +
    int smaxSetDB (int idx)
    +
    +

    Sets a non-default Redis database index to use for SMA-X before connecting to the SMA-X server.

    +
    Parameters
    + + +
    idxThe Redis database index to use (if not the default one)
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_ALREADY_OPEN if cannot alter the server configuration because we are already in a connected state.
    +
    See also
    smaxSetServer()
    +
    +smaxConnect()
    + +

    References smaxIsConnected().

    + +
    +
    + +

    ◆ smaxSetHostName()

    + +
    +
    + + + + + + + +
    void smaxSetHostName (const char * name)
    +
    +

    Changes the host name to the user-specified value instead of the default (leading component of the value returned by gethostname()). Subsequent calls to smaxGetHostName() will return the newly set value. An argument of NULL resets to the default.

    +
    Parameters
    + + +
    namethe host name to use, or NULL to revert to the default (leading component of gethostname()).
    +
    +
    +
    See also
    smaxGetHostName()
    + +
    +
    + +

    ◆ smaxSetPipelineConsumer()

    + +
    +
    + + + + + + + +
    int smaxSetPipelineConsumer (void(*)(RESP *) f)
    +
    +

    Change the pipeline response consumer function (from it's default or other previous consumer). It is a wrapper for redisxSetPipelineConsumer().

    +
    Parameters
    + + +
    fThe function to process ALL pipeline responses from Redis.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or else an error by redisxSetPipelineConsumer()
    +
    See also
    smaxSetPipelined()
    +
    +smaxIsPipelined()
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxSetPipelined()

    + +
    +
    + + + + + + + +
    int smaxSetPipelined (boolean isEnabled)
    +
    +

    Enable or disable pipelined write operations (enabled by default). When pipelining, share calls will return as soon as the request is sent to the Redis server, without waiting for a response. Instead, responses are consumed asynchronously by a dedicated thread, which will report errors to stderr. Pipelined writes can have a significant performance advantage over handshaking at the cost of one extra socket connection to Redis (dedicated to pipelining) and the extra thread consuming responses.

    +

    The default state of pipelined writes might vary by platform (e.g. enabled on Linux, disabled on LynxOS).

    +

    IMPORTANT: calls to smaxSetPipelined() must precede the call to smaxConnect().

    +
    Parameters
    + + +
    isEnabledTRUE to enable pipelined writes, FALSE to disable (default is enabled).
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_ALREADY_OPEN if cannot alter the server configuration because we are already in a connected state.
    +
    See also
    smaxIsPipelined()
    +
    +smaxSetPipelineConsumer()
    + +

    References smaxIsConnected().

    + +
    +
    + +

    ◆ smaxSetServer()

    + +
    +
    + + + + + + + + + + + +
    int smaxSetServer (const char * host,
    int port )
    +
    +

    Configures the SMA-X server before connecting.

    +
    Parameters
    + + + +
    hostThe SMA-X REdis server host name or IP address.
    portThe Redis port number on the SMA-X server, or &lt=0 to use the default
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_ALREADY_OPEN if cannot alter the server configuration because we are already in a connected state.
    +
    See also
    smaxSetAuth()
    +
    +smaxSetDB()
    +
    +smaxConnect()
    + +

    References smaxIsConnected().

    + +
    +
    + +

    ◆ smaxSetTcpBuf()

    + +
    +
    + + + + + + + +
    int smaxSetTcpBuf (int size)
    +
    +

    Set the size of the TCP/IP buffers (send and receive) for future client connections.

    +
    Parameters
    + + +
    size(bytes) requested buffer size, or <= 0 to use default value
    +
    +
    +
    See also
    smaxConnect;
    + +

    References smaxIsConnected().

    + +
    +
    + +

    ◆ smaxSetVerbose()

    + +
    +
    + + + + + + + +
    void smaxSetVerbose (boolean value)
    +
    +

    Enable or disable verbose reporting of all SMA-X operations (and possibly some details of them). Reporting is done on the standard output (stdout). It may be useful when debugging programs that use the SMA-X interface. Verbose reporting is DISABLED by default.

    +
    Parameters
    + + +
    valueTRUE to enable verbose reporting, or FALSE to disable.
    +
    +
    +
    See also
    smaxIsVerbose()
    + +
    +
    + +

    ◆ smaxShare()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    int smaxShare (const char * table,
    const char * key,
    const void * value,
    XType type,
    int count )
    +
    +

    Share the data into a Redis hash table over the interactive Redis client. It's a fire-and-forget type implementation, which sends the data to Redis, without waiting for confirmation of its arrival. The choice improves the efficiency and throughput, and minimizes execution time, of the call, but it also means that a pipelined pull request in quick succession, e.g. via smaxQueue(), may return a value on the pipeline client before this call is fully executed on the interactive Redis client.

    +

    (It is generally unlikely that you will follow this share call with a pipelined pull of the same variable. It would not only create superflous network traffic for no good reason, but it also would have unpredictable results. So, don't.)

    +
    Parameters
    + + + + + + +
    tableHash table name in which to share entry.
    keyVariable name under which the data is stored.
    valuePointer to the buffer whose data is to be shared.
    typeSMA-X variable type, e.g. X_FLOAT or X_CHARS(40), of the buffer.
    countNumber of 1D elements.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized. X_GROUP_INVALID if the table name is invalid. X_NAME_INVALID if the 'key' argument is invalid. X_SIZE_INVALID if count < 1 or count > X_MAX_ELEMENTS X_NULL if the 'value' argument is NULL. X_NO_SERVICE if there was no connection to the Redis server. X_FAILURE if there was an underlying failure.
    +
    See also
    smaxShareArray()
    +
    +smaxShareField()
    +
    +smaxShareStruct()
    + +

    References smaxShareArray().

    + +
    +
    + +

    ◆ smaxShareArray()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    int smaxShareArray (const char * table,
    const char * key,
    const void * ptr,
    XType type,
    int ndim,
    const int * sizes )
    +
    +

    Share a multidimensional array, such as an int[][][], or float[][], in a single atomic transaction.

    +
    Parameters
    + + + + + + + +
    tableHash table in which to write entry.
    keyVariable name under which the data is stored.
    ptrPointer to the data buffer, such as an int[][][] or float[][].
    typeSMA-X variable type, e.g. X_FLOAT or X_CHARS(40), of the buffer.
    ndimDimensionality of the data (0 <= ndim <= X_MAX_DIMS).
    sizesAn array of ints containing the sizes along each dimension.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized. X_GROUP_INVALID if the table name is invalid. X_NAME_INVALID if the 'key' argument is invalid. X_SIZE_INVALID if ndim or sizes are invalid. X_NULL if the 'value' argument is NULL. X_NO_SERVICE if there was no connection to the Redis server. X_FAILURE if there was an underlying failure.
    +
    See also
    smaxShare()
    + +

    References smaxShareField(), and smaxValuesToString().

    + +
    +
    + +

    ◆ smaxShareField()

    + +
    +
    + + + + + + + + + + + +
    int smaxShareField (const char * table,
    const XField * f )
    +
    +

    Share a field object, which may contain any SMA-X data type.

    +
    Parameters
    + + + +
    tableHash table in which to write entry.
    fPointer for XField holding the data to share.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized. X_GROUP_INVALID if the table name is invalid. X_NAME_INVALID if the 'key' argument is invalid. X_SIZE_INVALID if ndim or sizes are invalid. X_NULL if the 'value' argument is NULL. X_NO_SERVICE if there was no connection to the Redis server. X_FAILURE if there was an underlying failure.
    +
    See also
    smaxShare()
    +
    +smaxShareField()
    +
    +smaxShareStruct()
    +
    +xSetField()
    +
    +xGetField()
    + +

    References smaxShareStruct().

    + +
    +
    + +

    ◆ smaxShareStruct()

    + +
    +
    + + + + + + + + + + + +
    int smaxShareStruct (const char * id,
    const XStructure * s )
    +
    +

    Share a structure, and all its data including recursive sub-structures, in a single atromic transaction.

    +
    Parameters
    + + + +
    idStructure's ID, i.e. its own aggregated hash table name.
    sPointer to the structure data.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized. X_GROUP_INVALID if the table name is invalid. X_NAME_INVALID if the 'key' argument is invalid. X_NULL if the 'value' argument is NULL. X_NO_SERVICE if there was no connection to the Redis server. X_FAILURE if there was an underlying failure.
    +
    See also
    smaxShare()
    +
    +smaxShareField()
    +
    +xCreateStruct()
    + +

    References smaxCreateField().

    + +
    +
    + +

    ◆ smaxSubscribe()

    + +
    +
    + + + + + + + + + + + +
    int smaxSubscribe (const char * table,
    const char * key )
    +
    +

    Subscribes to a specific key(s) in specific group(s). Both the group and key names may contain Redis subscription patterns, e.g. '*' or '?', or bound characters in square-brackets, e.g. '[ab]'. The subscription only enables receiving update notifications from Redis for the specified variable or variables. After subscribing, you can either wait on the subscribed variables to change, or add callback functions to process subscribed variables changes, via smaxAddSubscriber().

    +
    Parameters
    + + + +
    tableVariable group pattern, i.e. hash-table names. (NULL is the same as '*').
    keyVariable name pattern. (if NULL then subscribes only to the table stem).
    +
    +
    +
    Returns
    X_SUCCESS if successfully subscribed to the Redis distribution channel. X_NO_SERVICE if there is no active connection to the Redis server. X_NULL if the channel argument is NULL X_NO_INIT if the SMA-X library was not initialized.
    +
    See also
    smaxUnsubscribe()
    +
    +smaxWaitOnSubscribed()
    +
    +smaxWaitOnSubscribedGroup()
    +
    +smaxWaitOnSubscribedVar()
    +
    +smaxWaitOnAnySubscribed()
    +
    +smaxAddSubscriber()
    + +
    +
    + +

    ◆ smaxUnsubscribe()

    + +
    +
    + + + + + + + + + + + +
    int smaxUnsubscribe (const char * table,
    const char * key )
    +
    +

    Unsubscribes from a specific key(s) in specific group(s). Both the group and key names may contain Redis subscription patterns, e.g. '*' or '?', or bound characters in square-brackets, e.g. '[ab]'. Unsubscribing will only stops the delivery of update notifications for the affected varuiables, but does not deactivate the associated callbacks for these added via smaxAddSubscriber(). Therefore you should also call smaxRemovesubscribers() as appropriate to deactivate actions that can no longer get triggered by updates.

    +
    Parameters
    + + + +
    tableVariable group pattern, i.e. structure or hash-table name(s) (NULL is the same as '*').
    keyVariable name pattern. (if NULL then unsubscribes only from the table stem).
    +
    +
    +
    Returns
    X_SUCCESS if successfully unsubscribed to the Redis distribution channel. X_NO_SERVICE if there is no active connection to the Redis server. X_NULL if the channel argument is NULL X_NO_INIT if the SMA-X library was not initialized.
    +
    See also
    smaxSubscribe()
    +
    +smaxRemoveSubscribers()
    + +
    +
    + +

    ◆ smaxWaitOnAnySubscribed()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxWaitOnAnySubscribed (char ** changedTable,
    char ** changedKey,
    int timeout )
    +
    +

    Waits until any variable was pushed on any host, returning both the host and variable name for the updated value. The variable must be already subscribed to with smaxSubscribe(), or else the wait will not receive update notifications.

    +
    Parameters
    + + + + +
    [out]changedTablePointer to the variable that points to the string buffer for the returned table name or NULL. The lease of the buffer is for the call only.
    [out]changedKeyPointer to the variable that points to the string buffer for the returned variable name or NULL. The lease of the buffer is for the call only.
    [in]timeout(s) Timeout value. 0 or negative values result in an indefinite wait.
    +
    +
    +
    Returns
    X_SUCCESS (0) if a variable was pushed on a host. X_NO_INIT if the SMA-X sharing was not initialized via smaxConnect(). X_NO_SERVICE if the connection was broken X_GROUP_INVALID if the buffer for the returned table name is NULL. X_NAME_INVALID if the buffer for the returned variable name is NULL. X_INTERRUPTED if smaxReleaseWaits() was called. X_INCOMPLETE if the wait timed out.
    +
    See also
    smaxSubscribe()
    +
    +smaxWaitOnSubscribed()
    +
    +smaxWaitOnSubscribedGroup()
    +
    +smaxReleaseWaits()
    + +

    References RELEASEID, and smaxIsConnected().

    + +
    +
    +
    +
    + + + + diff --git a/apidoc/html/smax_8c.js b/apidoc/html/smax_8c.js new file mode 100644 index 0000000..f402bf2 --- /dev/null +++ b/apidoc/html/smax_8c.js @@ -0,0 +1,42 @@ +var smax_8c = +[ + [ "smaxAddConnectHook", "smax_8c.html#ad63c425cc3affdf8bc803c7ff8dd6e30", null ], + [ "smaxAddDisconnectHook", "smax_8c.html#a65ae161b28cfe4369709fae1d3ea678c", null ], + [ "smaxAddSubscriber", "smax_8c.html#a827dd87397943f3384605f87116b630c", null ], + [ "smaxConnect", "smax_8c.html#a146fb2ed8512919dc91ecad6d08c74d1", null ], + [ "smaxConnectTo", "smax_8c.html#ad960c22b119ff2493a319945a9dd55a5", null ], + [ "smaxDisconnect", "smax_8c.html#a9d1e6ffa837d3582a8165e326cc44bea", null ], + [ "smaxGetHostName", "smax_8c.html#ac704fea3e664905af780d2566e3c74b6", null ], + [ "smaxGetKeys", "smax_8c.html#a2544d1fa602e812004e1d68500024ae0", null ], + [ "smaxGetProgramID", "smax_8c.html#abc07a7599e0bac1be15bbcb6b63d4710", null ], + [ "smaxGetRedis", "smax_8c.html#a533fbe770158afe876a3dafa78ba2195", null ], + [ "smaxIsConnected", "smax_8c.html#a95cbb68e3eb751219ab3363c93a4840b", null ], + [ "smaxIsPipelined", "smax_8c.html#af6f57a699b784fc67534cff0abd9573b", null ], + [ "smaxIsVerbose", "smax_8c.html#a980232c82ed7ebf5425c60db65f828c0", null ], + [ "smaxKeyCount", "smax_8c.html#a7030106bbe70220c97b1e9e3a4633ff4", null ], + [ "smaxPull", "smax_8c.html#afb7eec789669c3d3f416857d3615ace6", null ], + [ "smaxReconnect", "smax_8c.html#aafc75a2e8b8858b8ff0f16e0e73dbd03", null ], + [ "smaxReleaseWaits", "smax_8c.html#a14bc33c30d27be9e2954ae7831099f1c", null ], + [ "smaxRemoveConnectHook", "smax_8c.html#a4708c3c699781abec237045c48719f3d", null ], + [ "smaxRemoveDisconnectHook", "smax_8c.html#a70cdc3f1bf6b97248b5b8ba6df4dc044", null ], + [ "smaxRemoveSubscribers", "smax_8c.html#a77d04f4fbb447f169d40b2a24fa7cf71", null ], + [ "smaxSetAuth", "smax_8c.html#a097b12d3bbb43175084b0b0a2f55339c", null ], + [ "smaxSetDB", "smax_8c.html#a79fba7411b5afa132457a6828ff5ed9f", null ], + [ "smaxSetHostName", "smax_8c.html#a886e2ed23987201a9808f1c99806b44a", null ], + [ "smaxSetPipelineConsumer", "smax_8c.html#a542b4c264a49b61a6cd25881290df1d1", null ], + [ "smaxSetPipelined", "smax_8c.html#a8d7a3f57360d8e505baa78e445a53875", null ], + [ "smaxSetServer", "smax_8c.html#a78cf94f007034f63b609cbe72b8047b0", null ], + [ "smaxSetTcpBuf", "smax_8c.html#ac42ee8e8128aac0695c68660f04fd196", null ], + [ "smaxSetVerbose", "smax_8c.html#ac43709380b9ad92133a22ae0d52d107c", null ], + [ "smaxShare", "smax_8c.html#aee07f085e12283ad96f42c4d77430880", null ], + [ "smaxShareArray", "smax_8c.html#a1b116e8ffa85c30991ce6d8afb0319e0", null ], + [ "smaxShareField", "smax_8c.html#a0da1227278e6bc105c7dbdba14fd884a", null ], + [ "smaxShareStruct", "smax_8c.html#ab6a1590c953abc1c37fed841cd3a903a", null ], + [ "smaxSubscribe", "smax_8c.html#a53614ba57a594135c13b64a2d89eaa43", null ], + [ "smaxUnsubscribe", "smax_8c.html#af3a5d7bc565ab7de0ac1dd8fafc93f14", null ], + [ "smaxWaitOnAnySubscribed", "smax_8c.html#a89db98657eab826392d6099d21fff14c", null ], + [ "GET_STRUCT", "smax_8c.html#abc25cf33d9f3d6262a6fe3ffd94a85ae", null ], + [ "HGET_WITH_META", "smax_8c.html#ac5e36a13b5d67f497b15ab44b5a315af", null ], + [ "HMSET_WITH_META", "smax_8c.html#a561e3c013e65d6b0703bf1e574d7b821", null ], + [ "HSET_WITH_META", "smax_8c.html#a6d21bc913aebbf4a95c6c4f6f18da3b4", null ] +]; \ No newline at end of file diff --git a/apidoc/html/smax_8h.html b/apidoc/html/smax_8h.html new file mode 100644 index 0000000..c723fb1 --- /dev/null +++ b/apidoc/html/smax_8h.html @@ -0,0 +1,5724 @@ + + + + + + + +smax-clib: include/smax.h File Reference + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + +
    +
    smax-clib v0.9 +
    +
    A C/C++ client library for SMA-X
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    + +
    smax.h File Reference
    +
    +
    + + + + + + + + + + + + + + + + + +

    +Data Structures

    struct  XCoordinateAxis
     Structure that defines a coordinate axis in an XCoordinateSystem for an SMA-X data array. More...
     
    struct  XCoordinateSystem
     Structure that defines a coordinate system, with one or more XCoordinateAxis. More...
     
    struct  XMessage
     SMA-X program message. More...
     
    struct  XMeta
     SMA-X standard metadata. More...
     
    struct  XSyncPoint
     Synchronization point that can be waited upon when queueing pipelined pulls. More...
     
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    +Macros

    +#define META_COORDS   "<coords>"
     Redis hash table in which data coordinates system descriptions are stored.
     
    +#define META_DESCRIPTION   "<descriptions>"
     Redis hash table in which variable descriptions are stored.
     
    +#define META_UNIT   "<units>"
     Redis hash table in which data physical unit names are stored.
     
    +#define SMAX_DEFAULT_HOSTNAME   "smax"
     Host name of Redis server used for SMA-X.
     
    +#define SMAX_DEFAULT_MAX_QUEUED   1024
     Maximum number of pull requests allowed to be queued at once.
     
    +#define SMAX_DEFAULT_PIPELINE_ENABLED   TRUE
     Whether pipelining is enabled by default.
     
    +#define SMAX_DIMS   "<dims>"
     Redis meta table where variable dimensions are stored.
     
    +#define SMAX_MSG_DEBUG   "debug"
     Program debug messages (also e.g. traces).
     
    +#define SMAX_MSG_DETAIL   "detail"
     Program detail (i.e. verbose messages).
     
    +#define SMAX_MSG_ERROR   "error"
     Program errors.
     
    +#define SMAX_MSG_INFO   "info"
     Informational program message.
     
    +#define SMAX_MSG_PROGRESS   "progress"
     Program detail (i.e. verbose messages).
     
    +#define SMAX_MSG_STATUS   "status"
     Program status update.
     
    +#define SMAX_MSG_WARNING   "warning"
     Program warnings.
     
    +#define SMAX_ORIGIN_LENGTH   80
     (bytes) Maximum length of 'origin' meatdata, including termination.
     
    +#define SMAX_ORIGINS   "<origins>"
     Redis meta table where variable origins are stored.
     
    +#define SMAX_PIPE_READ_TIMEOUT_MILLIS   3000
     (ms) Timeout for pipelined (queued) pull requests
     
    +#define SMAX_READS   "<reads>"
     Redis meta table where the number of times a variable has been read is stored.
     
    +#define SMAX_RECONNECT_RETRY_SECONDS   3
     (s) Time between reconnection attempts on lost SMA-X connections.
     
    +#define SMAX_RESTORE_QUEUE_ON_RECONNECT   TRUE
     Whether read queues are restored if SMA-X is disconnected/reconnected.
     
    +#define SMAX_SCRIPTS   "scripts"
     Redis table in which the built-in LUA script hashes are stored.
     
    +#define SMAX_TIMESTAMPS   "<timestamps>"
     Redis meta table where variable timestamps are stored.
     
    #define SMAX_TYPES
     Redis meta table where variable types are stored.
     
    +#define SMAX_UPDATES   SMAX_UPDATES_ROOT X_SEP
     PUB/SUB message channel heade for hash table updates.
     
    +#define SMAX_UPDATES_LENGTH
     String length of SMA-X update channel prefix.
     
    +#define SMAX_UPDATES_ROOT   "smax"
     Notification class for SMA-X updates.
     
    +#define SMAX_WRITES   "<writes>"
     Redis meta table where the number of times a variable has been written is stored.
     
    #define X_META_INIT   { 0, X_UNKNOWN, -1, {0}, -1 }
     
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    +Functions

    int smax2xField (XField *f)
     
    int smax2xStruct (XStructure *s)
     
    int smaxAddConnectHook (void(*setupCall)(void))
     
    int smaxAddDefaultMessageProcessor (const char *host, const char *prog, const char *type)
     
    int smaxAddDisconnectHook (void(*cleanupCall)(void))
     
    int smaxAddMessageProcessor (const char *host, const char *prog, const char *type, void(*f)(XMessage *))
     
    int smaxAddSubscriber (const char *stem, RedisSubscriberCall f)
     
    int smaxConnect ()
     
    int smaxConnectTo (const char *server)
     
    XField * smaxCreate1DField (const char *name, XType type, int size, const void *value)
     
    XField * smaxCreateBooleanField (const char *name, boolean value)
     
    XCoordinateSystemsmaxCreateCoordinateSystem (int nAxis)
     
    XField * smaxCreateDoubleField (const char *name, double value)
     
    XField * smaxCreateField (const char *name, XType type, int ndim, const int *sizes, const void *value)
     
    XField * smaxCreateIntField (const char *name, int value)
     
    XField * smaxCreateLongField (const char *name, long long value)
     
    XMetasmaxCreateMeta ()
     
    XField * smaxCreateScalarField (const char *name, XType type, const void *value)
     
    XField * smaxCreateStringField (const char *name, const char *value)
     
    XSyncPointsmaxCreateSyncPoint ()
     
    int smaxDeletePattern (const char *pattern)
     
    void smaxDestroyCoordinateSystem (XCoordinateSystem *coords)
     
    void smaxDestroySyncPoint (XSyncPoint *sync)
     
    int smaxDisconnect ()
     
    int smaxError (const char *func, int errorCode)
     
    const char * smaxErrorDescription (int code)
     
    int smaxGetArrayField (const XStructure *s, const char *name, void *dst, XType type, int count)
     
    boolean smaxGetBooleanField (const XStructure *s, const char *name, boolean defaultValue)
     
    XCoordinateAxissmaxGetCoordinateAxis (const char *id, int n)
     
    XCoordinateSystemsmaxGetCoordinateSystem (const char *table, const char *key)
     
    char * smaxGetDescription (const char *table, const char *key)
     
    double smaxGetDoubleField (const XStructure *s, const char *name, double defaultValue)
     
    char * smaxGetHostName ()
     
    char ** smaxGetKeys (const char *table, int *n)
     
    int smaxGetLazyCached (const char *table, const char *key, XType type, int count, void *value, XMeta *meta)
     
    int smaxGetLazyUpdateCount (const char *table, const char *key)
     
    long long smaxGetLongField (const XStructure *s, const char *name, long long defaultValue)
     
    int smaxGetMetaCount (const XMeta *m)
     
    char * smaxGetProgramID ()
     
    char * smaxGetRawField (const XStructure *s, const char *name, char *defaultValue)
     
    Redis * smaxGetRedis ()
     
    char * smaxGetScriptSHA1 (const char *scriptName, int *status)
     
    int smaxGetServerTime (struct timespec *t)
     
    double smaxGetTime (const char *timestamp)
     
    char * smaxGetUnits (const char *table, const char *key)
     
    int smaxIsConnected ()
     
    boolean smaxIsPipelined ()
     
    boolean smaxIsResilient ()
     
    boolean smaxIsVerbose ()
     
    int smaxKeyCount (const char *table)
     
    int smaxLazyCache (const char *table, const char *key, XType type)
     
    int smaxLazyEnd (const char *table, const char *key)
     
    int smaxLazyFlush ()
     
    int smaxLazyPull (const char *table, const char *key, XType type, int count, void *value, XMeta *meta)
     
    int smaxLazyPullChars (const char *table, const char *key, char *buf, int n)
     
    double smaxLazyPullDouble (const char *table, const char *key)
     
    double smaxLazyPullDoubleDefault (const char *table, const char *key, double defaultValue)
     
    long long smaxLazyPullLong (const char *table, const char *key, long long defaultValue)
     
    char * smaxLazyPullString (const char *table, const char *key)
     
    int smaxLazyPullStruct (const char *id, XStructure *s)
     
    int smaxParseTime (const char *timestamp, time_t *secs, long *nanosecs)
     
    int smaxPull (const char *table, const char *key, XType type, int count, void *value, XMeta *meta)
     
    double smaxPullDouble (const char *table, const char *key)
     
    double smaxPullDoubleDefault (const char *table, const char *key, double defaultValue)
     
    double * smaxPullDoubles (const char *table, const char *key, XMeta *meta, int *n)
     
    int smaxPullInt (const char *table, const char *key, int defaultValue)
     
    int * smaxPullInts (const char *table, const char *key, XMeta *meta, int *n)
     
    long long smaxPullLong (const char *table, const char *key, long long defaultValue)
     
    long long * smaxPullLongs (const char *table, const char *key, XMeta *meta, int *n)
     
    char * smaxPullMeta (const char *meta, const char *table, const char *key, int *status)
     
    char * smaxPullRaw (const char *table, const char *key, XMeta *meta, int *status)
     
    char * smaxPullString (const char *table, const char *key)
     
    char ** smaxPullStrings (const char *table, const char *key, XMeta *meta, int *n)
     
    XStructure * smaxPullStruct (const char *name, XMeta *meta, int *status)
     
    double smaxPullTime (const char *table, const char *key)
     
    XType smaxPullTypeDimension (const char *table, const char *key, int *ndim, int *sizes)
     
    int smaxPushMeta (const char *meta, const char *table, const char *key, const char *value)
     
    int smaxQueue (const char *table, const char *key, XType type, int count, void *value, XMeta *meta)
     
    int smaxQueueCallback (void(*f)(void *), void *arg)
     
    int smaxReconnect ()
     
    int smaxReleaseWaits ()
     
    int smaxRemoveConnectHook (void(*setupCall)(void))
     
    int smaxRemoveDisconnectHook (void(*cleanupCall)(void))
     
    int smaxRemoveMessageProcessor (int id)
     
    int smaxRemoveSubscribers (RedisSubscriberCall f)
     
    void smaxResetMeta (XMeta *m)
     
    int smaxSendDebug (const char *msg)
     
    int smaxSendDetail (const char *msg)
     
    int smaxSendError (const char *msg)
     
    int smaxSendInfo (const char *msg)
     
    int smaxSendProgress (double fraction, const char *msg)
     
    int smaxSendStatus (const char *msg)
     
    int smaxSendWarning (const char *msg)
     
    int smaxSetAuth (const char *username, const char *password)
     
    int smaxSetCoordinateAxis (const char *id, int n, const XCoordinateAxis *axis)
     
    int smaxSetCoordinateSystem (const char *table, const char *key, const XCoordinateSystem *coords)
     
    int smaxSetDB (int idx)
     
    int smaxSetDescription (const char *table, const char *key, const char *description)
     
    void smaxSetHostName (const char *name)
     
    int smaxSetMaxPendingPulls (int n)
     
    void smaxSetMessageSenderID (const char *id)
     
    void smaxSetOrigin (XMeta *m, const char *origin)
     
    int smaxSetPipelineConsumer (void(*f)(RESP *))
     
    int smaxSetPipelined (boolean isEnabled)
     
    void smaxSetResilient (boolean value)
     
    void smaxSetResilientExit (boolean value)
     
    int smaxSetServer (const char *host, int port)
     
    int smaxSetTcpBuf (int size)
     
    int smaxSetUnits (const char *table, const char *key, const char *unit)
     
    void smaxSetVerbose (boolean value)
     
    int smaxShare (const char *table, const char *key, const void *value, XType type, int count)
     
    int smaxShareArray (const char *table, const char *key, const void *value, XType type, int ndim, const int *sizes)
     
    int smaxShareBoolean (const char *table, const char *key, boolean value)
     
    int smaxShareBooleans (const char *table, const char *key, const boolean *values, int n)
     
    int smaxShareBytes (const char *table, const char *key, const char *values, int n)
     
    int smaxShareDouble (const char *table, const char *key, double value)
     
    int smaxShareDoubles (const char *table, const char *key, const double *values, int n)
     
    int smaxShareField (const char *table, const XField *f)
     
    int smaxShareFloats (const char *table, const char *key, const float *values, int n)
     
    int smaxShareHex (const char *table, const char *key, long long value)
     
    int smaxShareInt (const char *table, const char *key, long long value)
     
    int smaxShareInts (const char *table, const char *key, const int *values, int n)
     
    int smaxShareLongs (const char *table, const char *key, const long long *values, int n)
     
    int smaxShareShorts (const char *table, const char *key, const short *values, int n)
     
    int smaxShareString (const char *table, const char *key, const char *sValue)
     
    int smaxShareStrings (const char *table, const char *key, const char **sValues, int n)
     
    int smaxShareStruct (const char *id, const XStructure *s)
     
    int smaxStringToValues (const char *str, void *value, XType type, int count, int *parsed)
     
    char * smaxStringType (XType type)
     
    int smaxSubscribe (const char *table, const char *key)
     
    int smaxSync (XSyncPoint *sync, int timeoutMillis)
     
    int smaxTimestamp (char *buf)
     
    int smaxTimeToString (const struct timespec *time, char *buf)
     *‍/
     
    XType smaxTypeForString (const char *type)
     
    int smaxUnpackStrings (const char *data, int len, int count, char **dst)
     
    int smaxUnsubscribe (const char *table, const char *key)
     
    char * smaxValuesToString (const void *value, XType type, int count, char *trybuf, int trylength)
     
    int smaxWaitOnAnySubscribed (char **changedTable, char **changedKey, int timeout)
     
    int smaxWaitOnSubscribed (const char *table, const char *key, int timeout)
     
    int smaxWaitOnSubscribedGroup (const char *matchTable, char **changedKey, int timeout)
     
    int smaxWaitOnSubscribedVar (const char *matchKey, char **changedTable, int timeout)
     
    int smaxWaitQueueComplete (int timeoutMillis)
     
    int x2smaxField (XField *f)
     
    int x2smaxStruct (XStructure *s)
     
    +

    Detailed Description

    +
    Date
    Jan 26, 2018
    +
    Author
    Attila Kovacs
    +

    Macro Definition Documentation

    + +

    ◆ SMAX_TYPES

    + +
    +
    + + + + +
    #define SMAX_TYPES
    +
    + +

    Redis meta table where variable types are stored.

    +

    Character arrays a treated somewhat differently, with the element size bundled in the type, to allow variable length strings to be properly parsed into them without overflow...

    + +
    +
    + +

    ◆ X_META_INIT

    + +
    +
    + + + + +
    #define X_META_INIT   { 0, X_UNKNOWN, -1, {0}, -1 }
    +
    +

    Default initialized for SMA-X medatadata structure. You should always initialize local metadata with this.

    + +
    +
    +

    Function Documentation

    + +

    ◆ smax2xField()

    + +
    +
    + + + + + + + +
    int smax2xField (XField * f)
    +
    +

    Converts SMA-X field with serialized string value storage to a standard xchange field with a native value storage.

    +
    Parameters
    + + +
    fPointer to field to convert
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NULL if the input field or the deserialized value is NULL, X_TYPE_INVALID if the field is of a type that cannot be deserialized, or else an error code returned by smaxStringToValues().
    +
    See also
    x2smaxField()
    +
    +smax2xStruct()
    + +

    References smax2xStruct(), and smaxStringToValues().

    + +
    +
    + +

    ◆ smax2xStruct()

    + +
    +
    + + + + + + + +
    int smax2xStruct (XStructure * s)
    +
    +

    Converts an SMA-X structure with serialized string value storage to a standard xchange structure with a native value storage.

    +
    Parameters
    + + +
    sPointer to structure to convert
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_STRUCT_INVALID if the structure is NULL, or had a NULL substructure, or else an error code returned by smax2xField().
    +
    See also
    x2smaxStruct()
    +
    +smax2xField()
    + +

    References smax2xField().

    + +
    +
    + +

    ◆ smaxAddConnectHook()

    + +
    +
    + + + + + + + +
    int smaxAddConnectHook (void(*)(void) setupCall)
    +
    +

    Add a callback function for when SMA-X is connected. It's a wrapper to redisxAddConnectHook().

    +
    Parameters
    + + +
    setupCallCallback function
    +
    +
    +
    Returns
    X_SUCCESS (0) or an error code (<0) from redisxAddConnectHook().
    +
    See also
    smaxRemoveConnectHook()
    +
    +smaxConnect()
    +
    +smaxConnectTo()
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxAddDefaultMessageProcessor()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxAddDefaultMessageProcessor (const char * host,
    const char * prog,
    const char * type )
    +
    +

    Report messages to stdout/stderr in default formats.

    +
    Parameters
    + + + + +
    hostHost name where messages originate from, or "*" or NULL if any.
    progProgram name of message originator, or "*" or NULL if any.
    typeMessage type, or "*" or NULL if any.
    +
    +
    +
    Returns
    Serial ID number (> 0) of the message processor, or X_NULL.
    + +

    References smaxAddMessageProcessor().

    + +
    +
    + +

    ◆ smaxAddDisconnectHook()

    + +
    +
    + + + + + + + +
    int smaxAddDisconnectHook (void(*)(void) cleanupCall)
    +
    +

    Add a callback function for when SMA-X is disconnected. It's a wrapper to redisxAddDisconnectHook().

    +
    Parameters
    + + +
    cleanupCallCallback function
    +
    +
    +
    Returns
    X_SUCCESS (0) or an error code (<0) from redisxAddConnectHook().
    +
    See also
    smaxRemoveDisconnectHook()
    +
    +smaxDisconnect()
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxAddMessageProcessor()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxAddMessageProcessor (const char * host,
    const char * prog,
    const char * type,
    void(*)(XMessage *) f )
    +
    +

    Adds a message processor function for a specific host (or all hosts), a specific program (or all programs), and a specific message type (or all message types).

    +
    Parameters
    + + + + + +
    hostHost name where messages originate from, or "*" or NULL if any.
    progProgram name of message originator, or "*" or NULL if any.
    typeMessage type, or "*" or NULL if any.
    fCallback function
    +
    +
    +
    Returns
    Serial ID number (> 0) of the message processor, or X_NULL if callback function is null, or X_FAILURE if malloc failed.
    +
    See also
    smaxRemoveMessageProcessor()
    + +

    References MESSAGES_PREFIX, smaxGetRedis(), and smaxRemoveMessageProcessor().

    + +
    +
    + +

    ◆ smaxAddSubscriber()

    + +
    +
    + + + + + + + + + + + +
    int smaxAddSubscriber (const char * idStem,
    RedisSubscriberCall f )
    +
    +

    Add a subcriber (callback) function to process incoming PUB/SUB messages for a given SMA-X table (or id). The function should itself check that the channel receiving notification is indeed what it expectes before acting on it, as the callback routine will be invoked for any update inside the specified table, unless the table argument refers to a specific aggregate ID of a single variable. This call only registers the callback routine for SMA-X update notifications for variables that begin with the specified stem. You will still have to subscrive to any relevant variables with smaxSubscribe() to enable delivering update notifications for the variables of your choice.

    +
    Parameters
    + + + +
    idStemTable name or ID stem for which the supplied callback function will be invoked as long as the beginning of the PUB/SUB update channel matches the given stem. Alternatively, it can be a fully qualified SMA-X ID (of the form table:key) f a single variable.
    fThe function to call when there is an incoming PUB/SUB update to a channel starting with stem.
    +
    +
    +
    Returns
    X_SUCCESS if successful, or else an approriate error code by redisxAddSubscriber()
    +
    See also
    smaxSubscribe()
    + +

    References SMAX_UPDATES_ROOT, and smaxGetRedis().

    + +
    +
    + +

    ◆ smaxConnect()

    + +
    +
    + + + + + + + +
    int smaxConnect ()
    +
    +

    Initializes the SMA-X sharing library in this runtime instance.

    +
    Returns
    X_SUCCESS If the library was successfully initialized X_ALREADY_OPEN If SMA-X sharing was already open. X_NO_SERVICE If the there was an issue establishing the necessary network connection(s). X_NAME_INVALID If the redis server name lookup failed. X_NULL If the Redis IP address is NULL
    +
    See also
    smaxSetServer()
    +
    +smaxSetAuth()
    +
    +smaxConnectTo()
    +
    +smaxDisconnect()
    +
    +smaxReconnect()
    +
    +smaxIsConnected()
    + +

    References SMAX_DEFAULT_HOSTNAME, smaxAddConnectHook(), smaxAddDisconnectHook(), smaxAddSubscriber(), smaxGetProgramID(), smaxIsConnected(), smaxLazyFlush(), smaxReleaseWaits(), smaxSetPipelineConsumer(), smaxSetResilient(), and smaxTransmitErrorHandler().

    + +
    +
    + +

    ◆ smaxConnectTo()

    + +
    +
    + + + + + + + +
    int smaxConnectTo (const char * server)
    +
    +

    Initializes the SMA-X sharing library in this runtime instance with the specified Redis server. SMA-X is initialized in resilient mode, so that we'll automatically attempt to reconnect to the Redis server if the connection is severed (once it was established). If that is not the desired behavior, you should call smaxSetResilient(FALSE) after connecting.

    +
    Parameters
    + + +
    serverSMA-X Redis server name or IP address, e.g. "127.0.0.1".
    +
    +
    +
    Returns
    X_SUCCESS If the library was successfully initialized X_NO_SERVICE If the there was an issue establishing the necessary network connection(s).
    +
    See also
    smaxConnect()
    +
    +smaxDisconnect()
    +
    +smaxReconnect()
    +
    +smaxIsConnected()
    +
    +smaxSetResilient()
    + +

    References smaxConnect(), and smaxSetServer().

    + +
    +
    + +

    ◆ smaxCreate1DField()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    XField * smaxCreate1DField (const char * name,
    XType type,
    int size,
    const void * value )
    +
    +

    Creates a field for 1-D array of a given name and type using specified native values. It is like xCreate1DField() except that the field is created in serialized form.

    +
    Parameters
    + + + + + +
    nameField name
    typeStorage type, e.g. X_INT.
    sizeArray size.
    valuePointer to the native array in memory.
    +
    +
    +
    Returns
    A newly created field with the supplied data, or NULL if there was an error.
    +
    See also
    xSetField()
    + +

    References smaxCreateField().

    + +
    +
    + +

    ◆ smaxCreateBooleanField()

    + +
    +
    + + + + + + + + + + + +
    XField * smaxCreateBooleanField (const char * name,
    boolean value )
    +
    +

    Creates a field holding a single boolean value. It is like xCreateBooleanField() except that the field is created in serialized form.

    +
    Parameters
    + + + +
    nameField name
    valueAssociated value
    +
    +
    +
    Returns
    A newly created field with the supplied data, or NULL if there was an error.
    +
    See also
    xSetField()
    + +

    References smaxCreateScalarField().

    + +
    +
    + +

    ◆ smaxCreateCoordinateSystem()

    + +
    +
    + + + + + + + +
    XCoordinateSystem * smaxCreateCoordinateSystem (int nAxis)
    +
    +

    Creates a coordinate system with the desired dimension, and standard Cartesian coordinates with no labels, or units specified (NULL).

    +
    Parameters
    + + +
    nAxisDimension of the coordiante system, i.e. number of axes.
    +
    +
    +
    Returns
    Pointer to the new coordinate system structure, or NULL if the coordiate system could not be created as specified.
    +
    See also
    smaxDestroyCoordinateSystem()
    + +

    References XCoordinateSystem::axis, XCoordinateSystem::nAxis, and XCoordinateAxis::step.

    + +
    +
    + +

    ◆ smaxCreateDoubleField()

    + +
    +
    + + + + + + + + + + + +
    XField * smaxCreateDoubleField (const char * name,
    double value )
    +
    +

    Creates a field holding a single double-precision value. It is like xCreateDoubleField() except that the field is created in serialized form.

    +
    Parameters
    + + + +
    nameField name
    valueAssociated value
    +
    +
    +
    Returns
    A newly created field with the supplied data, or NULL if there was an error.
    +
    See also
    xSetField()
    + +

    References smaxCreateScalarField().

    + +
    +
    + +

    ◆ smaxCreateField()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    XField * smaxCreateField (const char * name,
    XType type,
    int ndim,
    const int * sizes,
    const void * value )
    +
    +

    Creates a generic field of a given name and type and dimensions using the specified native values. It is like xCreateField() except that the field is created in serialized form for SMA-X.

    +
    Parameters
    + + + + + + +
    nameField name
    typeStorage type, e.g. X_INT.
    ndimNumber of dimensionas (1:20). If ndim < 1, it will be reinterpreted as ndim=1, size[0]=1;
    sizesArray of sizes along each dimensions, with at least ndim elements, or NULL with ndim<1.
    valuePointer to the native data location in memory. Unless it is of type X_STRUCT, the data stored in the field is a copy (for type X_RAW) or serialized string (otherwise).
    +
    +
    +
    Returns
    A newly created field with the supplied data, or NULL if there was an error.
    +
    See also
    xSetField()
    + +

    References smaxValuesToString().

    + +
    +
    + +

    ◆ smaxCreateIntField()

    + +
    +
    + + + + + + + + + + + +
    XField * smaxCreateIntField (const char * name,
    int value )
    +
    +

    Creates a field holding a single integer value. It is like xCreateIntField() except that the field is created in serialized form.

    +
    Parameters
    + + + +
    nameField name
    valueAssociated value
    +
    +
    +
    Returns
    A newly created field with the supplied data, or NULL if there was an error.
    +
    See also
    xSetField()
    + +

    References smaxCreateScalarField().

    + +
    +
    + +

    ◆ smaxCreateLongField()

    + +
    +
    + + + + + + + + + + + +
    XField * smaxCreateLongField (const char * name,
    long long value )
    +
    +

    Creates a field holding a single wide (64-bit) integer value. It is like xCreateLongField() except that the field is created in serialized form.

    +
    Parameters
    + + + +
    nameField name
    valueAssociated value
    +
    +
    +
    Returns
    A newly created field with the supplied data, or NULL if there was an error.
    +
    See also
    xSetField()
    + +

    References smaxCreateScalarField().

    + +
    +
    + +

    ◆ smaxCreateMeta()

    + +
    +
    + + + + + + + +
    XMeta * smaxCreateMeta ()
    +
    +

    Creates a new SMA-X metadata object with defaults. Effectively the same as calling calloc() followed by xResetMeta().

    +
    Returns
    Pointer to a new metadata object initialized to defaults.
    +
    See also
    X_META_INIT
    + +

    References smaxResetMeta().

    + +
    +
    + +

    ◆ smaxCreateScalarField()

    + +
    +
    + + + + + + + + + + + + + + + + +
    XField * smaxCreateScalarField (const char * name,
    XType type,
    const void * value )
    +
    +

    Creates a scalar field of a given name and type using the specified native value. It is like xCreateScalarField() except that the field is created in serialized form.

    +
    Parameters
    + + + + +
    nameField name
    typeStorage type, e.g. X_INT.
    valuePointer to the native data location in memory.
    +
    +
    +
    Returns
    A newly created scalar field with the supplied data, or NULL if there was an error.
    +
    See also
    xSetField()
    + +

    References smaxCreate1DField().

    + +
    +
    + +

    ◆ smaxCreateStringField()

    + +
    +
    + + + + + + + + + + + +
    XField * smaxCreateStringField (const char * name,
    const char * value )
    +
    +

    Creates a field holding a single string value. It is like xCreateStringField() except that the field is created in serialized form.

    +
    Parameters
    + + + +
    nameField name
    valueAssociated value
    +
    +
    +
    Returns
    A newly created field referencing the supplied string, or NULL if there was an error.
    + +

    References smaxCreateScalarField().

    + +
    +
    + +

    ◆ smaxCreateSyncPoint()

    + +
    +
    + + + + + + + +
    XSyncPoint * smaxCreateSyncPoint ()
    +
    +

    Creates a synchronization point that can be waited upon until all elements queued prior to creation are processed (retrieved from the database.

    +
    Returns
    Pointer to a newly created synchronization point that can be waited upon.
    +
    See also
    smaxSync()
    +
    +smaxQueue()
    +
    +smaxQueueCallback()
    + +

    References XSyncPoint::isComplete, XSyncPoint::lock, and XSyncPoint::status.

    + +
    +
    + +

    ◆ smaxDeletePattern()

    + +
    +
    + + + + + + + +
    int smaxDeletePattern (const char * pattern)
    +
    +

    Deletes variables and metadata from SMA-X.

    +
    Parameters
    + + +
    patternGlob variable name pattern
    +
    +
    +
    Returns
    The number of variables deleted from the SQL DB
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxDestroyCoordinateSystem()

    + +
    +
    + + + + + + + +
    void smaxDestroyCoordinateSystem (XCoordinateSystem * coords)
    +
    +

    Deallocates a coordinate system structure.

    +
    Parameters
    + + +
    coordsPointer to the coordinate system to discard.
    +
    +
    +
    See also
    smaxCreateCoordinateSystem()
    + +

    References XCoordinateSystem::axis.

    + +
    +
    + +

    ◆ smaxDestroySyncPoint()

    + +
    +
    + + + + + + + +
    void smaxDestroySyncPoint (XSyncPoint * s)
    +
    +

    Destroys a synchronization point, releasing the memory space allocated to it.

    +
    Parameters
    + + +
    sPointer to the synchronization point to discard.
    +
    +
    + +

    References XSyncPoint::isComplete, and XSyncPoint::lock.

    + +
    +
    + +

    ◆ smaxDisconnect()

    + +
    +
    + + + + + + + +
    int smaxDisconnect ()
    +
    +

    Disables the SMA-X sharing capability, closing underlying network connections.

    +
    Returns
    X_SUCCESS (0) if the sharing was properly ended. X_NO_INIT if SMA-X was has not been started prior to this call.
    +
    See also
    smaxConnect()
    +
    +smaxConnectTo()
    +
    +smaxReconnect()
    +
    +smaxIsConnected()
    + +

    References smaxIsConnected().

    + +
    +
    + +

    ◆ smaxError()

    + +
    +
    + + + + + + + + + + + +
    int smaxError (const char * func,
    int errorCode )
    +
    +

    Prints a descriptive error message to stderr, and returns the error code.

    +
    Parameters
    + + + +
    funcString that describes the function or location where the error occurred.
    errorCodeError code that describes the failure.
    +
    +
    +
    Returns
    Same error code as specified on input.
    + +

    References smaxErrorDescription().

    + +
    +
    + +

    ◆ smaxErrorDescription()

    + +
    +
    + + + + + + + +
    const char * smaxErrorDescription (int code)
    +
    +

    Returns a string description for one of the RM error codes.

    +
    Parameters
    + + +
    codeOne of the error codes defined in 'xchange.h' or in 'smax.h' (e.g. X_NO_PIPELINE)
    +
    +
    + +
    +
    + +

    ◆ smaxGetArrayField()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    int smaxGetArrayField (const XStructure * s,
    const char * name,
    void * dst,
    XType type,
    int count )
    +
    +

    Gets the data of an SMA-X structure field as an array of values of the specified type and element count. The field's data will be truncated or padded with zeroes to provide the requested element count always.

    +
    Parameters
    + + + + + + +
    sPointer to SMA-X structure
    nameField name
    [out]dstArray to return values in.
    typeType of data.
    countNumber of elements in return array. The field data will be truncated or padded as necessary.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_STRUCT_INVALID if the input structure is NULL, X_NULL if dst is NULL, X_SIZE_INVALID if n is 0 or negative, X_NAME_INVALID if the structure does not have a field by the specified name, or else an error returned by smaxStringtoValues().
    + +

    References smaxStringToValues().

    + +
    +
    + +

    ◆ smaxGetBooleanField()

    + +
    +
    + + + + + + + + + + + + + + + + +
    boolean smaxGetBooleanField (const XStructure * s,
    const char * name,
    boolean defaultValue )
    +
    +

    Returns the first value in a structure's field as an integer, or the specified default value if there is no such field in the structure, or the content cannot be parse into an integer.

    +
    Parameters
    + + + + +
    sPointer to the XStructure.
    nameField name
    defaultValueValue to return if no corresponding integer field value.
    +
    +
    +
    Returns
    The (first) field value as a long long, or the default value if there is no such field.
    +
    See also
    xGetField()
    + +
    +
    + +

    ◆ smaxGetCoordinateAxis()

    + +
    +
    + + + + + + + + + + + +
    XCoordinateAxis * smaxGetCoordinateAxis (const char * id,
    int n )
    +
    +

    Returns the n'th coordinate axis for a given SMA-X coordinate system table id.

    +
    Parameters
    + + + +
    idFully qualified SMA-X coordinate system ID.
    nThe (0-based) index of the coordinate axis
    +
    +
    +
    Returns
    Pointer to a newly allocated XCoordinateAxis structure or NULL if the axis is undefined, or could not be retrieved from the database.
    +
    See also
    smaxSetCoordinateAxis()
    + +

    References XCoordinateAxis::name, XCoordinateAxis::refIndex, XCoordinateAxis::refValue, smaxGetRedis(), XCoordinateAxis::step, and XCoordinateAxis::unit.

    + +
    +
    + +

    ◆ smaxGetCoordinateSystem()

    + +
    +
    + + + + + + + + + + + +
    XCoordinateSystem * smaxGetCoordinateSystem (const char * table,
    const char * key )
    +
    +

    Returns the coordinate system, if any, associated to a given SMA-X variable.

    +
    Parameters
    + + + +
    tableHash table name.
    keyVariable / field name in table.
    +
    +
    +
    Returns
    A newly allocated coordinate system structure, or NULL.
    +
    See also
    smaxSetCoordinateSystem()
    +
    +smaxGetCoordinateAxis()
    + +

    References XCoordinateSystem::axis, META_COORDS, XCoordinateSystem::nAxis, and smaxGetCoordinateAxis().

    + +
    +
    + +

    ◆ smaxGetDescription()

    + +
    +
    + + + + + + + + + + + +
    char * smaxGetDescription (const char * table,
    const char * key )
    +
    +

    Returns a concise description of a variable.

    +
    Parameters
    + + + +
    tableHash table name.
    keyVariable / field name in table.
    +
    +
    +
    Returns
    Variable description or NULL or empty string if the variable has no description assiciated with it.
    +
    See also
    smaxSetDescription()
    + +

    References META_DESCRIPTION, and smaxPullMeta().

    + +
    +
    + +

    ◆ smaxGetDoubleField()

    + +
    +
    + + + + + + + + + + + + + + + + +
    double smaxGetDoubleField (const XStructure * s,
    const char * name,
    double defaultValue )
    +
    +

    Returns the first value in a structure's field as a double precision float, or the specified default value if there is no such field in the structure, or the content cannot be parse into an double.

    +
    Parameters
    + + + + +
    sPointer to the XStructure.
    nameField name
    defaultValueValue to return if no corresponding integer field value.
    +
    +
    +
    Returns
    The (first) field value as a double, or the specified default if there is no such field.
    +
    See also
    xGetField()
    + +
    +
    + +

    ◆ smaxGetHostName()

    + +
    +
    + + + + + + + +
    char * smaxGetHostName ()
    +
    +

    Returns the host name on which this program is running. It returns a reference to the same static variable every time. As such you should never call free() on the returned value. Note, that only the leading part of the host name is returned, so for a host that is registered as 'somenode.somedomain' only 'somenode' is returned.

    +
    Returns
    The host name string (leading part only).
    +
    See also
    smaxSetHostName()
    + +
    +
    + +

    ◆ smaxGetKeys()

    + +
    +
    + + + + + + + + + + + +
    char ** smaxGetKeys (const char * table,
    int * n )
    +
    +

    Returns a snapshot of the key names stored in a given Redis hash table, ot NULL if there was an error.

    +
    Parameters
    + + + +
    tableHost name or owner ID whose variable to count.
    [out]nPointer to which the number of keys (>=0) or an error (<0) is returned. An error returned by redisxGetKeys(), or else:
    +
    +
    +

    X_NO_INIT if the SMA-X sharing was not initialized, e.g. via smaxConnect(). X_GROUP_INVALID if the table name is invalid. X_NULL if the output 'n' pointer is NULL.

    +
    Returns
    An array of pointers to the names of Redis keys.
    +
    See also
    smaxKeyCount()
    + +
    +
    + +

    ◆ smaxGetLazyCached()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    int smaxGetLazyCached (const char * table,
    const char * key,
    XType type,
    int count,
    void * value,
    XMeta * meta )
    +
    +

    Retrieve a variable from the local cache (if available), or else pull from the SMA-X database. If local caching was not previously eanbled, it will be enabled with this call, so that subsequent calls will always return data from the locally updated cache with minimal overhead and effectively no latency.

    +
    Parameters
    + + + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    typeThe SMA-X variable type, e.g. X_FLOAT or X_CHARS(40), of the buffer.
    countThe number of elements to retrieve
    valuePointer to the native data buffer in which to restore values
    metaOptional metadata pointer, or NULL if metadata is not required.
    +
    +
    +
    Returns
    X_SUCCESS (0), or X_NO_SERVICE is SMA-X is not accessible, or another error (<0) from smax.h or xchange.h.
    +
    See also
    sa smaxLazyCache()
    +
    +sa smaxLaxyPull()
    + +
    +
    + +

    ◆ smaxGetLazyUpdateCount()

    + +
    +
    + + + + + + + + + + + +
    int smaxGetLazyUpdateCount (const char * table,
    const char * key )
    +
    +

    Returns the actual number of times a variable has been updated from SMA-X. It may be useful information when deciding if lazy pulling is appropriate (it is if the number of pull requests exceeds the actual number of transfers significantly).

    +
    Parameters
    + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    +
    +
    +
    Returns
    The number of times a variable has been updated, or -1 if the variable is not being monitored, or if the arguments are invalid.
    + +
    +
    + +

    ◆ smaxGetLongField()

    + +
    +
    + + + + + + + + + + + + + + + + +
    long long smaxGetLongField (const XStructure * s,
    const char * name,
    long long defaultValue )
    +
    +

    Returns the first value in a structure's field as an integer, or the specified default value if there is no such field in the structure, or the content cannot be parse into an integer.

    +
    Parameters
    + + + + +
    sPointer to the XStructure.
    nameField name
    defaultValueValue to return if no corresponding integer field value.
    +
    +
    +
    Returns
    The (first) field value as a long long, or the default value if there is no such field.
    +
    See also
    xGetField()
    + +
    +
    + +

    ◆ smaxGetMetaCount()

    + +
    +
    + + + + + + + +
    int smaxGetMetaCount (const XMeta * m)
    +
    +

    Returns the number of elements stored from a metadata.

    +
    Parameters
    + + +
    mpointer to metadata that defines the dimension and shape of elements.
    +
    +
    +
    Returns
    the total number of elements represented by the metadata
    + +

    References XMeta::storeDim, and XMeta::storeSizes.

    + +
    +
    + +

    ◆ smaxGetProgramID()

    + +
    +
    + + + + + + + +
    char * smaxGetProgramID ()
    +
    +

    Returns the SMA-X program ID.

    +
    Returns
    The SMA-X program ID as <hostname>:<programname>, e.g. "hal9000:statusServer".
    + +

    References smaxGetHostName().

    + +
    +
    + +

    ◆ smaxGetRawField()

    + +
    +
    + + + + + + + + + + + + + + + + +
    char * smaxGetRawField (const XStructure * s,
    const char * name,
    char * defaultValue )
    +
    +

    Returns the string value in a structure's field, or the specified default value if there is no such field in the structure.

    +
    Parameters
    + + + + +
    sPointer to the XStructure.
    nameField name
    defaultValueValue to return if no corresponding integer field value.
    +
    +
    +
    Returns
    The field's string (raw) value, or the specified default if there is no such field.
    +
    See also
    xGetField()
    + +
    +
    + +

    ◆ smaxGetRedis()

    + +
    +
    + + + + + + + +
    Redis * smaxGetRedis ()
    +
    +

    Returns the Redis connection information for SMA-X

    +
    Returns
    The structure containing the Redis connection data.
    +
    See also
    smaxConnect()
    +
    +smaxConnectTo()
    +
    +smaxIsConnected()
    + +
    +
    + +

    ◆ smaxGetScriptSHA1()

    + +
    +
    + + + + + + + + + + + +
    char * smaxGetScriptSHA1 (const char * scriptName,
    int * status )
    +
    +

    Gets the SHA1 script ID for the currently loaded script with the specified name.

    +
    Parameters
    + + + +
    scriptNameCase-sensitive name of the script, e.g. "GetStruct".
    statusPointer int which to return status, which is X_SUCCESS if the SHA1 id was successfully obtained, or else an appropriate error code.
    +
    +
    +
    Returns
    String buffer with the SHA1 key or NULL if it could not be retrieved. (The caller is responsible freeing the buffer after use.)
    + +

    References SMAX_SCRIPTS, and smaxGetRedis().

    + +
    +
    + +

    ◆ smaxGetServerTime()

    + +
    +
    + + + + + + + +
    int smaxGetServerTime (struct timespec * t)
    +
    +

    Returns the current time on the Redis server instance.

    +
    Parameters
    + + +
    tPointer to a timespec structure in which to return the server time.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NO_INIT if not connected to SMA-X, or X_NULL if either argument is NULL, or X_PARSE_ERROR if could not parse the response, or another error returned by redisxCheckRESP().
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxGetTime()

    + +
    +
    + + + + + + + +
    double smaxGetTime (const char * timestamp)
    +
    +

    Returns the a sub-second precision UNIX time value for the given SMA-X timestamp

    +
    Parameters
    + + +
    timestampThe string timestamp returned by SMA-X
    +
    +
    +
    Returns
    Corresponding UNIX time with sub-second precision, or NAN if the input could not be parsed.
    + +

    References smaxParseTime().

    + +
    +
    + +

    ◆ smaxGetUnits()

    + +
    +
    + + + + + + + + + + + +
    char * smaxGetUnits (const char * table,
    const char * key )
    +
    +

    Returns the physical unit name, if any, for the given variable.

    +
    Parameters
    + + + +
    tableHash table name.
    keyVariable / field name in table.
    +
    +
    +
    Returns
    Unit name (e.g. "W / Hz"), or NULL or empty string if the variable has no designated physical unit.
    +
    See also
    smaxSetUnits()
    + +

    References META_UNIT, and smaxPullMeta().

    + +
    +
    + +

    ◆ smaxIsConnected()

    + +
    +
    + + + + + + + +
    int smaxIsConnected ()
    +
    +

    Checks whether SMA-X sharing is currently open (by a preceding call to smaxConnect() call.

    +
    See also
    smaxConnect()
    +
    +smaxConnectTo()
    +
    +smaxDisconnect()
    +
    +smaxReconnect()
    + +
    +
    + +

    ◆ smaxIsPipelined()

    + +
    +
    + + + + + + + +
    boolean smaxIsPipelined ()
    +
    +

    Check if SMA-X is configured with pipeline mode enabled.

    +
    Returns
    TRUE (1) if the pipeline is enabled, or else FALSE (0)
    +
    See also
    smaxSetPipelined()
    + +
    +
    + +

    ◆ smaxIsResilient()

    + +
    +
    + + + + + + + +
    boolean smaxIsResilient ()
    +
    +

    Checks whether the resiliency feature has been enabled.

    +
    Returns
    TRUE if enabled, otherwise FALSE.
    +
    See also
    smaxSetResilient()
    + +
    +
    + +

    ◆ smaxIsVerbose()

    + +
    +
    + + + + + + + +
    boolean smaxIsVerbose ()
    +
    +

    Checks id verbose reporting is enabled.

    +
    Returns
    TRUE if verbose reporting is enabled, otherwise FALSE.
    +
    See also
    smaxSetVerbose()
    + +
    +
    + +

    ◆ smaxKeyCount()

    + +
    +
    + + + + + + + +
    int smaxKeyCount (const char * table)
    +
    +

    Retrieve the current number of variables stored on host (or owner ID).

    +
    Parameters
    + + +
    tableHash table name.
    +
    +
    +
    Returns
    The number of keys (fields) in the specified table (>= 0), or an error code (<0), such as: X_NO_INIT if the SMA-X sharing was not initialized, e.g. via smaConnect(). X_GROUP_INVALID if the table name is invalid. or one of the errors (<0) returned by redisxRequest().
    +
    See also
    smaxGetKeys()
    + +
    +
    + +

    ◆ smaxLazyCache()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxLazyCache (const char * table,
    const char * key,
    XType type )
    +
    +

    Specify that a specific variable should be cached for minimum overhead lazy access. When a variable is lazy cached its local copy is automatically updated in the background so that accessing it is always nearly instantaneous. Lazy caching is a good choice for variables that change less frequently than they are polled typically. For variables that change frequently (ans used less frequently), lazy caching is not a great choice since it consumes network bandwidth even when the variable is not being accessed.

    +

    Once a variable is lazy cached, it can be accessed instantaneously via smaxGetLazyCached() without any blocking network operations.

    +
    Parameters
    + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    typeThe SMA-X variable type, e.g. X_FLOAT or X_CHARS(40), of the buffer.
    +
    +
    +
    Returns
    X_SUCCESS (0) or X_NO_SERVICE.
    +
    See also
    smaxGetLazyCached()
    + +
    +
    + +

    ◆ smaxLazyEnd()

    + +
    +
    + + + + + + + + + + + +
    int smaxLazyEnd (const char * table,
    const char * key )
    +
    +

    Stops processing lazy updates in the background for a given variable.

    +
    Parameters
    + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    +
    +
    +
    Returns
    X_SUCCESS (0)
    +
    See also
    smaxLazyFlush()
    +
    +smaxLazyPull()
    + +
    +
    + +

    ◆ smaxLazyFlush()

    + +
    +
    + + + + + + + +
    int smaxLazyFlush ()
    +
    +

    Discards caches for all lazy variables (i.e. stops all subscriptions to variable updates, at least until the next smaxLazyPull() call). Generally speaking, it's a good idea to call this routine when one is done using a set of lazy variables for the time being, but want to avoid the tedium of calling smaxLazyEnd() individually for each of them. Note however, that after flushing the lazy caches, the fist lazy call following for each variable will inevitably result in a real SMA-X pull. So use it carefully!

    +
    Returns
    Number of monitor points flushed.
    +
    See also
    smaxLazyPull()
    +
    +smaxLazyEnd()
    + +

    References smaxRemoveSubscribers().

    + +
    +
    + +

    ◆ smaxLazyPull()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    int smaxLazyPull (const char * table,
    const char * key,
    XType type,
    int count,
    void * value,
    XMeta * meta )
    +
    +

    Poll an infrequently changing variable without stressing out the network or the SMA-X database. The first lazy pull for a variable will fetch its value from SMA-X and subscribe to update notifications. Subsequent smaxLazyPull() calls to the same variable will retrieve its value from a local cache (without contacting SMA-X) as long as it is unchanged.

    +

    Note, after you are done using a variable that has been lazy pulled, you should call smaxLazyEnd() to signal that it no longer requires to be cached and updated in the background, or call smaxLazyFlush() to flush all lazy caches for all lazy variables (if that is what you want).

    +
    Parameters
    + + + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    typeThe SMA-X variable type, e.g. X_FLOAT or X_CHARS(40), of the buffer.
    countThe number of points to retrieve into the buffer.
    valuePointer to the buffer to which the data is to be retrieved.
    metaPointer to metadata or NULL if no metadata is needed.
    +
    +
    +
    Returns
    X_SUCCESS (0) on success, or else an error code (<0) of smaxPull().
    +
    See also
    smaxLazyEnd()
    +
    +smaxLazyFlush()
    +
    +smaxPull()
    +
    +smaxQueue()
    + +
    +
    + +

    ◆ smaxLazyPullChars()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxLazyPullChars (const char * table,
    const char * key,
    char * buf,
    int n )
    +
    +

    Lazy pulls a string value into the specified string buffer.

    +
    Parameters
    + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    bufBuffer to fill with stored data
    nNumber of bytes to fill in buffer. The retrieved data will be truncated as necessary.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or the error code (<0) returned by smaxLazyPull().
    + +

    References smaxLazyPull().

    + +
    +
    + +

    ◆ smaxLazyPullDouble()

    + +
    +
    + + + + + + + + + + + +
    double smaxLazyPullDouble (const char * table,
    const char * key )
    +
    +

    Returns a single double-precision value for a given SMA-X variable, or NAN if the value could not be retrieved.

    +
    Parameters
    + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    +
    +
    +
    Returns
    The floating-point value stored in SMA-X, or NaN if the value could not be retrieved.
    +
    See also
    smaxLazyPullDoubleDefault()
    +
    +smaxPullDouble()
    + +

    References smaxLazyPullDoubleDefault().

    + +
    +
    + +

    ◆ smaxLazyPullDoubleDefault()

    + +
    +
    + + + + + + + + + + + + + + + + +
    double smaxLazyPullDoubleDefault (const char * table,
    const char * key,
    double defaultValue )
    +
    +

    Returns a single double-precision value for a given SMA-X variable, or a default value if the value could not be retrieved.

    +
    Parameters
    + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    defaultValueThe value to return in case of an error.
    +
    +
    +
    Returns
    The floating-point value stored in SMA-X, or the specified default if the value could not be retrieved.
    +
    See also
    smaxLazyPullDouble()
    +
    +smaxPullDoubleDefault()
    + +

    References smaxLazyPull().

    + +
    +
    + +

    ◆ smaxLazyPullLong()

    + +
    +
    + + + + + + + + + + + + + + + + +
    long long smaxLazyPullLong (const char * table,
    const char * key,
    long long defaultValue )
    +
    +

    Returns a single integer value for a given SMA-X variable, or a default value if the value could not be retrieved.

    +
    Parameters
    + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    defaultValueThe value to return in case of an error.
    +
    +
    +
    Returns
    The long integer value stored in SMA-X, or the specified default if the value could not be retrieved.
    +
    See also
    smaxPullLong()
    + +

    References smaxLazyPull().

    + +
    +
    + +

    ◆ smaxLazyPullString()

    + +
    +
    + + + + + + + + + + + +
    char * smaxLazyPullString (const char * table,
    const char * key )
    +
    +

    Returns a single string value for a given SMA-X variable, or a NULL if the value could not be retrieved.

    +
    Parameters
    + + + +
    tableHash table name.
    keyVariable name under which the data is stored.
    +
    +
    +
    Returns
    Pointer to the string value stored in SMA-X, or NULL if the value could not be retrieved.
    +
    See also
    smaxPullString()
    + +

    References smaxLazyPull().

    + +
    +
    + +

    ◆ smaxLazyPullStruct()

    + +
    +
    + + + + + + + + + + + +
    int smaxLazyPullStruct (const char * id,
    XStructure * s )
    +
    +

    Lazy pulls data into a structure, discarding any prior data that the structure might contain.

    +
    Parameters
    + + + +
    [in]idAggregate structure ID.
    [out]sDestination structure to populate with the retrieved fields
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or the error code (<0) returned by smaxLazyPull().
    +
    See also
    smaxPullStruct()
    +
    +xCreateStruct()
    + +

    References smaxLazyPull().

    + +
    +
    + +

    ◆ smaxParseTime()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxParseTime (const char * timestamp,
    time_t * secs,
    long * nanosecs )
    +
    +

    Parses a timestamp into broken-down UNIX time.

    +
    Parameters
    + + + + +
    [in]timestampTimestamp string as returned in redis queries;
    [out]secsPointer to the returned UNIX time (seconds).
    [out]nanosecsPointer to the retuned sub-second remainder as nanoseconds, or NULL if nor requested.
    +
    +
    +
    Returns
    X_SUCCESS(0) if the timestamp was successfully parsed. X_NULL if there was no timestamp (empty or invalid string), or the secs argument is NULL. X_PARSE_ERROR if the seconds could not be parsed. 1 if there was an error parsing the nanosec part. X_NULL if the secs arhument is NULL
    + +
    +
    + +

    ◆ smaxPull()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    int smaxPull (const char * table,
    const char * key,
    XType type,
    int count,
    void * value,
    XMeta * meta )
    +
    +

    Pull data from the specified hash table. This calls data via the interactive client to Redis.

    +
    Parameters
    + + + + + + + +
    [in]tableHash table name.
    [in]keyVariable name under which the data is stored.
    [in]typeSMA-X variable type, e.g. X_FLOAT or X_CHARS(40), of the buffer.
    [in]countNumber of points to retrieve into the buffer.
    [out]valuePointer to the buffer to which the data is to be retrieved.
    [out]metaPointer to metadata or NULL if no metadata is needed.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized. X_GROUP_INVALID if the 'table' argument is invalid. X_NAME_INVALID if the 'key' argument is invalid. X_NULL if an essential argument is NULL or contains NULL. X_NO_SERVICE if there was no connection to the Redis server. X_FAILURE if there was an underlying failure.
    +
    See also
    smaxLazyPull()
    +
    +smaxQueue()
    + +
    +
    + +

    ◆ smaxPullDouble()

    + +
    +
    + + + + + + + + + + + +
    double smaxPullDouble (const char * table,
    const char * key )
    +
    +

    Returns a single floating-point value for a given SMA-X variable, or a NAN if the value could not be retrieved.

    +
    Parameters
    + + + +
    tableHash table name.
    keyVariable name under which the data is stored.
    +
    +
    +
    Returns
    The floating-point value stored in SMA-X, or NAN if the value could not be retrieved.
    +
    See also
    smaxLazyPullDouble()
    +
    +smaxPullDoubleDefault()
    + +

    References smaxPullDoubleDefault().

    + +
    +
    + +

    ◆ smaxPullDoubleDefault()

    + +
    +
    + + + + + + + + + + + + + + + + +
    double smaxPullDoubleDefault (const char * table,
    const char * key,
    double defaultValue )
    +
    +

    Returns a single floating-point value for a given SMA-X variable, or a specified default value if the SMA-X value could not be retrieved.

    +
    Parameters
    + + + + +
    tableHash table name.
    keyVariable name under which the data is stored.
    defaultValueThe value to return in case of an error.
    +
    +
    +
    Returns
    The floating-point value stored in SMA-X, or the specified default if the value could not be retrieved.
    +
    See also
    smaxLazyPullDoubleDefault()
    +
    +smaxPullDouble()
    + +

    References smaxPull().

    + +
    +
    + +

    ◆ smaxPullDoubles()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    double * smaxPullDoubles (const char * table,
    const char * key,
    XMeta * meta,
    int * n )
    +
    +

    Returns a dynamically allocated array of doubles stored in an SMA-X variable.

    +
    Parameters
    + + + + + +
    [in]tableThe hash table name.
    [in]keyThe variable name under which the data is stored.
    [out]meta(optional) Pointer to metadata to be filled or NULL if not required.
    [out]nPointer to which the number of double is returned (if *n > 0) or else an error code.
    +
    +
    +
    Returns
    Pointer to C double[] array containing *n elements, or NULL.
    +
    See also
    smaxPullDouble()
    +
    +smaxPullFloats()
    + +
    +
    + +

    ◆ smaxPullInt()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxPullInt (const char * table,
    const char * key,
    int defaultValue )
    +
    +

    Returns a single integer value for a given SMA-X variable, or a default value if the value could not be retrieved.

    +
    Parameters
    + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    defaultValueThe value to return in case of an error.
    +
    +
    +
    Returns
    The integer value stored in SMA-X, or the specified default if the value could not be retrieved.
    +
    See also
    smaxLazyPullInt()
    +
    +smaxPullInts()
    +
    +smaPullLong()
    + +

    References smaxPull().

    + +
    +
    + +

    ◆ smaxPullInts()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int * smaxPullInts (const char * table,
    const char * key,
    XMeta * meta,
    int * n )
    +
    +

    Returns a dynamically allocated array of integers stored in an SMA-X variable.

    +
    Parameters
    + + + + + +
    [in]tableThe hash table name.
    [in]keyThe variable name under which the data is stored.
    [out]meta(optional) Pointer to metadata to be filled or NULL if not required.
    [out]nPointer to which the number of integers is returned (if *n > 0) or else an error code.
    +
    +
    +
    Returns
    Pointer to C int[] array containing *n elements, or NULL.
    +
    See also
    smaxPullShorts()
    +
    +smaxPullLongs()
    +
    +smaxPullInt()
    + +
    +
    + +

    ◆ smaxPullLong()

    + +
    +
    + + + + + + + + + + + + + + + + +
    long long smaxPullLong (const char * table,
    const char * key,
    long long defaultValue )
    +
    +

    Returns a single integer value for a given SMA-X variable, or a default value if the value could not be retrieved.

    +
    Parameters
    + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    defaultValueThe value to return in case of an error.
    +
    +
    +
    Returns
    The integer value stored in SMA-X, or the specified default if the value could not be retrieved.
    +
    See also
    smaxLazyPullLong()
    +
    +smaxPullLongs()
    +
    +smaxPullInt()
    + +

    References smaxPull().

    + +
    +
    + +

    ◆ smaxPullLongs()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    long long * smaxPullLongs (const char * table,
    const char * key,
    XMeta * meta,
    int * n )
    +
    +

    Returns a dynamically allocated array of long long (int64) integers stored in an SMA-X variable.

    +
    Parameters
    + + + + + +
    [in]tableThe hash table name.
    [in]keyThe variable name under which the data is stored.
    [out]meta(optional) Pointer to metadata to be filled or NULL if not required.
    [out]nPointer to which the number of integers is returned (if *n > 0) or else an error code.
    +
    +
    +
    Returns
    Pointer to C int[] array containing *n elements, or NULL.
    +
    See also
    smaxPullInts()
    +
    +smaxPullShorts()
    +
    +smaxPullLong()
    + +
    +
    + +

    ◆ smaxPullMeta()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    char * smaxPullMeta (const char * meta,
    const char * table,
    const char * key,
    int * status )
    +
    +

    Retrieves a metadata string value for a given variable from the database

    +
    Parameters
    + + + + + +
    metaRoot meta table name, usually something like "<metaname>".
    tableHash table name.
    keyVariable / field name in table.
    statusPointer to int in which to return a X_SUCCESS or an error code.
    +
    +
    +
    Returns
    The string metadata value or NULL.
    +
    See also
    setPushMeta()
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxPullRaw()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    char * smaxPullRaw (const char * table,
    const char * key,
    XMeta * meta,
    int * status )
    +
    +

    Returns a dynamically allocated buffer with the raw string value stored in SMA-X. This call can also be used to get single string values from SMA-X, since for single string the stored raw value is simply the string itself. However, to properly retrieve string arrays, you want to use smaxPullStrings() instead.

    +
    Parameters
    + + + + + +
    [in]tableThe hash table name.
    [in]keyThe variable name under which the data is stored.
    [out]meta(optional) Pointer to metadata to be filled or NULL if not required.
    [out]statusPointer int which an error status is returned.
    +
    +
    +
    Returns
    Pointer to C array containing the elements of the specified type, or NULL.
    +
    See also
    smaxPullStrings()
    + +

    References smaxPull().

    + +
    +
    + +

    ◆ smaxPullString()

    + +
    +
    + + + + + + + + + + + +
    char * smaxPullString (const char * table,
    const char * key )
    +
    +

    Returns a single string value for a given SMA-X variable, or a NULL if the value could not be retrieved.

    +
    Parameters
    + + + +
    tableHash table name.
    keyVariable name under which the data is stored.
    +
    +
    +
    Returns
    Pouinter to the string value stored in SMA-X, or NULL if the value could not be retrieved.
    +
    See also
    smaxLazyPullString()
    +
    +smaxPullStrings()
    + +

    References smaxPull().

    + +
    +
    + +

    ◆ smaxPullStrings()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    char ** smaxPullStrings (const char * table,
    const char * key,
    XMeta * meta,
    int * n )
    +
    +

    Returns an array of pointers to individuals strings inside the retrieved contiguous data buffer. Thus, to discard the returned data after use, you must first discard the underlying buffer (as pointed by the first element) before discarding the array of pointers themselves. E.g.:

    +

    char **array = smaxPullStrings("mygroup", "myfield", &meta); ... if(array != NULL) { free(array[0]); // discards the underlying contiguous buffer free(array); // discards the array of pointers. }

    +
    Parameters
    + + + + + +
    [in]tableThe hash table name.
    [in]keyThe variable name under which the data is stored.
    [out]meta(optional) Pointer to metadata to be filled or NULL if not required.
    [out]nPointer to which the number of double is returned (if *n > 0) or else an error code.
    +
    +
    +
    Returns
    Pointer to a an array of strings (char *) containing *n elements, or NULL.
    +
    See also
    smaxPullString()
    +
    +smaxPullRaw()
    + +

    References smaxGetMetaCount(), smaxPullRaw(), XMeta::storeBytes, and X_META_INIT.

    + +
    +
    + +

    ◆ smaxPullStruct()

    + +
    +
    + + + + + + + + + + + + + + + + +
    XStructure * smaxPullStruct (const char * id,
    XMeta * meta,
    int * status )
    +
    +

    Returns a dynamically allocated XStrucure for the specified hashtable in SMA-X.

    +
    Parameters
    + + + + +
    [in]idAggregated structure ID.
    [out]meta(optional) Pointer to metadata to be filled or NULL if not required.
    [out]statusPointer int which an error status is returned.
    +
    +
    +
    Returns
    Pointer to an XStructure, or NULL.
    +
    See also
    smaxLazyPullStruct()
    +
    +xDestroyStruct()
    + +

    References smaxPull().

    + +
    +
    + +

    ◆ smaxPullTime()

    + +
    +
    + + + + + + + + + + + +
    double smaxPullTime (const char * table,
    const char * key )
    +
    +

    Retrieves the timestamp for a given variable from the database.

    +
    Parameters
    + + + +
    [in]tableHash table name (or NULL if key is an aggregate ID).
    [in]keyVariable / field name in table.
    +
    +
    +
    Returns
    (s) UNIX timestamp, as fractional seconds since 1 Jan 1970, or NAN if there was an error.
    +
    See also
    setPushMeta()
    + +

    References SMAX_TIMESTAMPS, and smaxPullMeta().

    + +
    +
    + +

    ◆ smaxPullTypeDimension()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    XType smaxPullTypeDimension (const char * table,
    const char * key,
    int * ndim,
    int * sizes )
    +
    +

    Retrieves the timestamp for a given variable from the database.

    +
    Parameters
    + + + + + +
    [in]tableHash table name (or NULL if key is an aggregate ID).
    [in]keyVariable / field name in table.
    [out]ndimPointer to integer in which to return the dimensionality of the variable, or NULL if not requested.
    [out]sizesArray to store sizes along each dimension, which should hold X_MAX_DIMS integers, or NULL if dimensions are not requested.
    +
    +
    +
    Returns
    Type of data stored under the specified table/key ID.
    +
    See also
    setPushMeta()
    + +

    References SMAX_DIMS, SMAX_TYPES, smaxPullMeta(), and smaxTypeForString().

    + +
    +
    + +

    ◆ smaxPushMeta()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxPushMeta (const char * meta,
    const char * table,
    const char * key,
    const char * value )
    +
    +

    Adds/updates metadata associated with an SMA-X variable. The data will be pushed via the Redis pipeline channel.

    +
    Parameters
    + + + + + +
    metaRoot meta table name, usually something like "<metaname>".
    tableHash table name.
    keyVariable / field name in table.
    valueMetadata string value.
    +
    +
    +
    Returns
    X_SUCCESS (0) if the metadata was successfully retrieved X_INCOMPLETE if the meatdata was successfully written but an update notification was not sent or else the return value of redisxSetValue()
    +
    See also
    smaxPullMeta(), redisxSetValue()
    + +

    References smaxGetProgramID(), and smaxGetRedis().

    + +
    +
    + +

    ◆ smaxQueue()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    int smaxQueue (const char * table,
    const char * key,
    XType type,
    int count,
    void * value,
    XMeta * meta )
    +
    +

    Queues a pull requests for pipelined data retrieval. Because pipelined pulls are executed on a separate Redis client from the one used for sharing values, e.g. via smaxShare(), there is no guarantee as to the order of this pull operation and previously initiated shares from the same thread. This would only be an issue if you are trying to use queued read to read back a value you have just shared – which is not really a good use case anyway, as it generates network traffic for not real reason. But, if you must read back a value you have shared, you probably should use a regular smaxPull() call to ensure ordering.

    +
    Parameters
    + + + + + + + +
    tableHash table name.
    keyVariable name under which the data is stored.
    typeSMA-X variable type, e.g. X_FLOAT or X_CHARS(40), of the buffer.
    countNumber of points to retrieve into the buffer.
    [out]valuePointer to the buffer to which the data is to be retrieved.
    [out]metaPointer to the corresponding metadata structure, or NULL.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful X_NAME_INVALID if the table and key are both NULL X_NULL if the value field is NULL or the return value of xQueue().
    +
    See also
    smaxPull()
    +
    +smaxLazyPull()
    +
    +smaxCreateSyncPoint()
    +
    +smaxQueueCallback()
    + +

    References SMAX_PIPE_READ_TIMEOUT_MILLIS.

    + +
    +
    + +

    ◆ smaxQueueCallback()

    + +
    +
    + + + + + + + + + + + +
    int smaxQueueCallback (void(*)(void *) f,
    void * arg )
    +
    +

    Adds a callback function to the queue to be called with the specified argument once all prior requests in the queue have been fullfilled (retrieved from the database).

    +

    As a general rule callbacks added to the pipeline should return very fast, and avoid blocking operations for the most part (using mutexes that may block for very short periods only may be excepted). If the user needs to do more processing, or make blocking calls (e.g. IO operartions) that may not return for longer periods, the callback should fire off processing in a separate thread, or else simply move the result into another asynchronous processing queue.

    +
    Parameters
    + + + +
    fThe callback function that takes a pointer argument
    argArgument to call the specified function with.
    +
    +
    +
    Returns
    X_SUCCESS (0) or else X_NULL if the function parameter is NULL.
    +
    See also
    smaxCreateSyncPoint()
    +
    +smaxQueue()
    + +
    +
    + +

    ◆ smaxReconnect()

    + +
    +
    + + + + + + + +
    int smaxReconnect ()
    +
    +

    Reconnects to the SMA-X server. It will try connecting repeatedly at regular intervals until the connection is made. If resilient mode is enabled, then locally accumulated shares will be sent to the Redis server upon reconnection. However, subscriptions are not automatically re-established. The caller is responsible for reinstate any necessary subscriptions after the reconnection or via an approproate connection hook.

    +
    Returns
    X_SUCCESS (0) if successful X_NO_INIT if SMA-X was never initialized.
    +

    or the error returned by redisxReconnect().

    +
    See also
    smaxConnect()
    +
    +smaxConnectTo()
    +
    +smaxDisconnect()
    +
    +smaxIsConnected()
    +
    +smaxSetResilient()
    +
    +smaxAddConnectHook()
    + +

    References SMAX_RECONNECT_RETRY_SECONDS.

    + +
    +
    + +

    ◆ smaxReleaseWaits()

    + +
    +
    + + + + + + + +
    int smaxReleaseWaits ()
    +
    +

    Unblocks all smax_wait*() calls, which will return X_REL_PREMATURE, as a result.

    +
    Returns
    X_SUCCESS (0)
    +
    See also
    smaxWaitOnAnySubscribed()
    + +

    References RELEASEID.

    + +
    +
    + +

    ◆ smaxRemoveConnectHook()

    + +
    +
    + + + + + + + +
    int smaxRemoveConnectHook (void(*)(void) setupCall)
    +
    +

    Remove a post-connection callback function. It's a wrapper to redisxRemoveConnectHook().

    +
    Parameters
    + + +
    setupCallCallback function
    +
    +
    +
    Returns
    X_SUCCESS (0) or an error code (<0) from redisxAddConnectHook().
    +
    See also
    smaxAddConnectHook()
    +
    +smaxConnect()
    +
    +smaxConnectTo()
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxRemoveDisconnectHook()

    + +
    +
    + + + + + + + +
    int smaxRemoveDisconnectHook (void(*)(void) cleanupCall)
    +
    +

    Remove a post-cdisconnect callback function. It's a wrapper to redisxRemiveDisconnectHook().

    +
    Parameters
    + + +
    cleanupCallCallback function
    +
    +
    +
    Returns
    X_SUCCESS (0) or an error code (<0) from redisxAddConnectHook().
    +
    See also
    smaxAddDisconnectHook()
    +
    +smaxDisconnect()
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxRemoveMessageProcessor()

    + +
    +
    + + + + + + + +
    int smaxRemoveMessageProcessor (int id)
    +
    +

    Stops a running message processor.

    +
    Parameters
    + + +
    idMessage processor ID, as returned by smaxAddMessageProcessor()
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NULL if no message processor is running by that ID.
    +
    See also
    smaxAddMessageProcessor()
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxRemoveSubscribers()

    + +
    +
    + + + + + + + +
    int smaxRemoveSubscribers (RedisSubscriberCall f)
    +
    +

    Remove all instances of a subscriber callback function from the current list of functions processing PUB/SUB messages. This call only deactivates the callback routine, but does not stop the delivery of update notifications from the Redis server. You should therefore also call smaxUnsubscribe() as appropriate to stop notifications for variables that no longer have associated callbacks.

    +
    Parameters
    + + +
    fFunction to remove
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or else an error (<0) returned by redisxRemoveSubscriber().
    +
    See also
    smaxUnsubscribe()
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxResetMeta()

    + +
    +
    + + + + + + + +
    void smaxResetMeta (XMeta * m)
    +
    +

    Set metadata to their default values. After resetting the supplied metadata will have exactly the same content as if it were initialized with the X_META_INIT macro.

    +
    Parameters
    + + +
    mPointer to the metadata that is to be cleared.
    +
    +
    +
    See also
    X_META_INIT
    + +

    References X_META_INIT.

    + +
    +
    + +

    ◆ smaxSendDebug()

    + +
    +
    + + + + + + + +
    int smaxSendDebug (const char * msg)
    +
    +

    Broadcast a debugging message via SMA-X (e.g. program traces).

    +
    Parameters
    + + +
    msgMessage text
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an X error.
    + +

    References SMAX_MSG_DEBUG.

    + +
    +
    + +

    ◆ smaxSendDetail()

    + +
    +
    + + + + + + + +
    int smaxSendDetail (const char * msg)
    +
    +

    Broadcast non-essential verbose informational detail via SMA-X.

    +
    Parameters
    + + +
    msgMessage text
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an X error.
    + +

    References SMAX_MSG_DETAIL.

    + +
    +
    + +

    ◆ smaxSendError()

    + +
    +
    + + + + + + + +
    int smaxSendError (const char * msg)
    +
    +

    Broadcast an error message via SMA-X. Errors should be used for an issues that impair program functionality.

    +
    Parameters
    + + +
    msgMessage text
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an X error.
    +
    See also
    smaxSendWarning();
    +
    +smaxSendDebug();
    + +

    References SMAX_MSG_ERROR.

    + +
    +
    + +

    ◆ smaxSendInfo()

    + +
    +
    + + + + + + + +
    int smaxSendInfo (const char * msg)
    +
    +

    Broadcast an informational message via SMA-X. These should be confirmations or essential information reported back to users. Non-essential information should be sent with sendDetail() instead.

    +
    Parameters
    + + +
    msgMessage text
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an X error.
    +
    See also
    sendDetail()
    +
    +sendStatus()
    + +

    References SMAX_MSG_INFO.

    + +
    +
    + +

    ◆ smaxSendProgress()

    + +
    +
    + + + + + + + + + + + +
    int smaxSendProgress (double fraction,
    const char * msg )
    +
    +

    Broadcast a progress update over SMA-X.

    +
    Parameters
    + + + +
    fraction(0.0:1.0) Completion fraction.
    msgMessage text
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an X error.
    + +

    References SMAX_MSG_DETAIL.

    + +
    +
    + +

    ◆ smaxSendStatus()

    + +
    +
    + + + + + + + +
    int smaxSendStatus (const char * msg)
    +
    +

    Broadcast a program status update via SMA-X.

    +
    Parameters
    + + +
    msgMessage text
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an X error.
    +
    See also
    sendInfo()
    + +

    References SMAX_MSG_STATUS.

    + +
    +
    + +

    ◆ smaxSendWarning()

    + +
    +
    + + + + + + + +
    int smaxSendWarning (const char * msg)
    +
    +

    Broadcast a warning message via SMA-X. Warnings should be used for any potentially problematic issues that nonetheless do not impair program functionality.

    +
    Parameters
    + + +
    msgMessage text
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an X error.
    +
    See also
    smaxSendError();
    +
    +smaxSendDebug();
    + +

    References SMAX_MSG_WARNING.

    + +
    +
    + +

    ◆ smaxSetAuth()

    + +
    +
    + + + + + + + + + + + +
    int smaxSetAuth (const char * username,
    const char * password )
    +
    +

    Sets the SMA-X database authentication parameters (if any) before connecting to the SMA-X server.

    +
    Parameters
    + + + +
    usernameRedis ACL user name (if any), or NULL for no user-based authentication
    passwordRedis database password (if any), or NULL if the database is not password protected
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_ALREADY_OPEN if cannot alter the server configuration because we are already in a connected state.
    +
    See also
    smaxSetServer()
    +
    +smaxConnect()
    + +

    References smaxIsConnected().

    + +
    +
    + +

    ◆ smaxSetCoordinateAxis()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxSetCoordinateAxis (const char * id,
    int n,
    const XCoordinateAxis * axis )
    +
    +

    Defines the n'th coordinate axis for a given SMA-X coordinate system table id.

    +
    Parameters
    + + + + +
    idFully qualified SMA-X coordinate system ID.
    nThe (0-based) index of the coordinate axis
    axisPointer to the structure describing the coordinate axis.
    +
    +
    +
    Returns
    X_SUCCESS (0) if the coordinate axis was successfully set in the database. or else the return value of redisxMultiSet().
    +
    See also
    smaxSetCoordinateAxis(), redisxMultiSet()
    + +

    References XCoordinateAxis::name, XCoordinateAxis::refIndex, XCoordinateAxis::refValue, smaxGetRedis(), XCoordinateAxis::step, and XCoordinateAxis::unit.

    + +
    +
    + +

    ◆ smaxSetCoordinateSystem()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxSetCoordinateSystem (const char * table,
    const char * key,
    const XCoordinateSystem * coords )
    +
    +

    Sets the coordinate system metadata for data in the database.

    +
    Parameters
    + + + + +
    tableHash table name.
    keyVariable / field name in table.
    coordsPointer to the coordinate system structure associated to this variable.
    +
    +
    +
    Returns
    X_SUCCESS (0) if the coordinate system was successfully sent to SMA-X or else the first error encountered by xSetCoordinateAxis()
    +
    See also
    smaxGetCoordinateSystem()
    +
    +smaxSetCoordinateAxis()
    + +

    References XCoordinateSystem::axis, META_COORDS, XCoordinateSystem::nAxis, and smaxSetCoordinateAxis().

    + +
    +
    + +

    ◆ smaxSetDB()

    + +
    +
    + + + + + + + +
    int smaxSetDB (int idx)
    +
    +

    Sets a non-default Redis database index to use for SMA-X before connecting to the SMA-X server.

    +
    Parameters
    + + +
    idxThe Redis database index to use (if not the default one)
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_ALREADY_OPEN if cannot alter the server configuration because we are already in a connected state.
    +
    See also
    smaxSetServer()
    +
    +smaxConnect()
    + +

    References smaxIsConnected().

    + +
    +
    + +

    ◆ smaxSetDescription()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxSetDescription (const char * table,
    const char * key,
    const char * description )
    +
    +

    Sets the static description for a given SMA-X variable.

    +
    Parameters
    + + + + +
    tableHash table name.
    keyVariable / field name in table.
    descriptionConcise but descriptive summary of the meaning of the variable.
    +
    +
    +
    Returns
    X_SUCCESS (0) If successful or else the return value of smaxPushMeta()
    +
    See also
    smaxSetDescription(), smaxPushMeta()
    + +

    References META_DESCRIPTION, and smaxPushMeta().

    + +
    +
    + +

    ◆ smaxSetHostName()

    + +
    +
    + + + + + + + +
    void smaxSetHostName (const char * name)
    +
    +

    Changes the host name to the user-specified value instead of the default (leading component of the value returned by gethostname()). Subsequent calls to smaxGetHostName() will return the newly set value. An argument of NULL resets to the default.

    +
    Parameters
    + + +
    namethe host name to use, or NULL to revert to the default (leading component of gethostname()).
    +
    +
    +
    See also
    smaxGetHostName()
    + +
    +
    + +

    ◆ smaxSetMaxPendingPulls()

    + +
    +
    + + + + + + + +
    int smaxSetMaxPendingPulls (int n)
    +
    +

    Configures how many pull requests can be queued in when piped pulls are enabled. If the queue reaches the specified limit, no new pull requests can be submitted until responses arrive, draining the queue somewhat.

    +
    Parameters
    + + +
    nThe maximum number of pull requests that can be queued.
    +
    +
    +
    Returns
    TRUE if the argument was valid, and the queue size was set to it, otherwise FALSE
    + +
    +
    + +

    ◆ smaxSetMessageSenderID()

    + +
    +
    + + + + + + + +
    void smaxSetMessageSenderID (const char * id)
    +
    +

    Sets the sender ID for outgoing program messages. By default the sender ID is <host>:<program> for the program that calls this function, but it can be modified to use some other SMA-X style hierarchical ID also.

    +
    Parameters
    + + +
    idThe new sender ID for outgoing program messages, or NULL to reinstate the default <host>:<program> style ID. The argument is not referenced and can be deallocated as desired after the call without affecting the newly defined message ID.
    +
    +
    + +
    +
    + +

    ◆ smaxSetOrigin()

    + +
    +
    + + + + + + + + + + + +
    void smaxSetOrigin (XMeta * m,
    const char * origin )
    +
    +

    Sets the 'origin' field of an SMA-X metadata to the specified value, truncating as necessary to fit into the allotted fixed storage.

    +
    Parameters
    + + + +
    originThe origination information, usually as hostname:progname
    mPointer to metadata to set.
    +
    +
    + +

    References XMeta::origin, and SMAX_ORIGIN_LENGTH.

    + +
    +
    + +

    ◆ smaxSetPipelineConsumer()

    + +
    +
    + + + + + + + +
    int smaxSetPipelineConsumer (void(*)(RESP *) f)
    +
    +

    Change the pipeline response consumer function (from it's default or other previous consumer). It is a wrapper for redisxSetPipelineConsumer().

    +
    Parameters
    + + +
    fThe function to process ALL pipeline responses from Redis.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or else an error by redisxSetPipelineConsumer()
    +
    See also
    smaxSetPipelined()
    +
    +smaxIsPipelined()
    + +

    References smaxGetRedis().

    + +
    +
    + +

    ◆ smaxSetPipelined()

    + +
    +
    + + + + + + + +
    int smaxSetPipelined (boolean isEnabled)
    +
    +

    Enable or disable pipelined write operations (enabled by default). When pipelining, share calls will return as soon as the request is sent to the Redis server, without waiting for a response. Instead, responses are consumed asynchronously by a dedicated thread, which will report errors to stderr. Pipelined writes can have a significant performance advantage over handshaking at the cost of one extra socket connection to Redis (dedicated to pipelining) and the extra thread consuming responses.

    +

    The default state of pipelined writes might vary by platform (e.g. enabled on Linux, disabled on LynxOS).

    +

    IMPORTANT: calls to smaxSetPipelined() must precede the call to smaxConnect().

    +
    Parameters
    + + +
    isEnabledTRUE to enable pipelined writes, FALSE to disable (default is enabled).
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_ALREADY_OPEN if cannot alter the server configuration because we are already in a connected state.
    +
    See also
    smaxIsPipelined()
    +
    +smaxSetPipelineConsumer()
    + +

    References smaxIsConnected().

    + +
    +
    + +

    ◆ smaxSetResilient()

    + +
    +
    + + + + + + + +
    void smaxSetResilient (boolean value)
    +
    +

    Enables the resiliency feature of the library, which keeps track of local changes destined to the database when the database is not reachable, and sending all locally stored updates once the database comes online again. However, after sending all pending updates to the remote server, the program may exit (default behavior), unless smaxSetResilientExit() is set to FALSE (0), so that it can be restarted in a fresh state, setting up subscriptions and scripts again as necessary.

    +
    Parameters
    + + +
    valueTRUE (non-zero) to enable, or FALSE (0) to disable resiliency.
    +
    +
    +
    See also
    smaxIsResilient()
    +
    +smaxSetResilientExit()
    + +

    References smaxAddConnectHook(), and smaxRemoveConnectHook().

    + +
    +
    + +

    ◆ smaxSetResilientExit()

    + +
    +
    + + + + + + + +
    void smaxSetResilientExit (boolean value)
    +
    +

    Sets whether the program should exit in resilient mode, after having pushed all local updates. The default is to exit since the reconnecting in resilient mode does not by itself re-establish existing subscriptions. However, when subscriptions aren't used, or if they are set up as a connect hook, the user may want the program to simply continue. This is possible by passing FALSE (0) as the argument to this call. This setting only takes effect when resilient mode is enabled. Otherwise, the exit policy is set by the RedisX library.

    +
    Parameters
    + + +
    valueWhether to exit the program after all local updates have been pushed to SMA-X after a recovering from an outage.
    +
    +
    +
    See also
    smaxSetResilient()
    +
    +smaxAddConnectHook()
    + +
    +
    + +

    ◆ smaxSetServer()

    + +
    +
    + + + + + + + + + + + +
    int smaxSetServer (const char * host,
    int port )
    +
    +

    Configures the SMA-X server before connecting.

    +
    Parameters
    + + + +
    hostThe SMA-X REdis server host name or IP address.
    portThe Redis port number on the SMA-X server, or &lt=0 to use the default
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_ALREADY_OPEN if cannot alter the server configuration because we are already in a connected state.
    +
    See also
    smaxSetAuth()
    +
    +smaxSetDB()
    +
    +smaxConnect()
    + +

    References smaxIsConnected().

    + +
    +
    + +

    ◆ smaxSetTcpBuf()

    + +
    +
    + + + + + + + +
    int smaxSetTcpBuf (int size)
    +
    +

    Set the size of the TCP/IP buffers (send and receive) for future client connections.

    +
    Parameters
    + + +
    size(bytes) requested buffer size, or <= 0 to use default value
    +
    +
    +
    See also
    smaxConnect;
    + +

    References smaxIsConnected().

    + +
    +
    + +

    ◆ smaxSetUnits()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxSetUnits (const char * table,
    const char * key,
    const char * unit )
    +
    +

    Sets the physical unit name for a given SMA-X variable.

    +
    Parameters
    + + + + +
    tableHash table name.
    keyVariable / field name in table.
    unitStandard unit specification, e.g. "W / Hz" or "W Hz**{-1}".
    +
    +
    +
    Returns
    X_SUCCESS (0) If successful or else the return value of smaxPushMeta()
    +
    See also
    smaxGetUnits(), smaxPushMeta()
    + +

    References META_UNIT, and smaxPushMeta().

    + +
    +
    + +

    ◆ smaxSetVerbose()

    + +
    +
    + + + + + + + +
    void smaxSetVerbose (boolean value)
    +
    +

    Enable or disable verbose reporting of all SMA-X operations (and possibly some details of them). Reporting is done on the standard output (stdout). It may be useful when debugging programs that use the SMA-X interface. Verbose reporting is DISABLED by default.

    +
    Parameters
    + + +
    valueTRUE to enable verbose reporting, or FALSE to disable.
    +
    +
    +
    See also
    smaxIsVerbose()
    + +
    +
    + +

    ◆ smaxShare()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    int smaxShare (const char * table,
    const char * key,
    const void * value,
    XType type,
    int count )
    +
    +

    Share the data into a Redis hash table over the interactive Redis client. It's a fire-and-forget type implementation, which sends the data to Redis, without waiting for confirmation of its arrival. The choice improves the efficiency and throughput, and minimizes execution time, of the call, but it also means that a pipelined pull request in quick succession, e.g. via smaxQueue(), may return a value on the pipeline client before this call is fully executed on the interactive Redis client.

    +

    (It is generally unlikely that you will follow this share call with a pipelined pull of the same variable. It would not only create superflous network traffic for no good reason, but it also would have unpredictable results. So, don't.)

    +
    Parameters
    + + + + + + +
    tableHash table name in which to share entry.
    keyVariable name under which the data is stored.
    valuePointer to the buffer whose data is to be shared.
    typeSMA-X variable type, e.g. X_FLOAT or X_CHARS(40), of the buffer.
    countNumber of 1D elements.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized. X_GROUP_INVALID if the table name is invalid. X_NAME_INVALID if the 'key' argument is invalid. X_SIZE_INVALID if count < 1 or count > X_MAX_ELEMENTS X_NULL if the 'value' argument is NULL. X_NO_SERVICE if there was no connection to the Redis server. X_FAILURE if there was an underlying failure.
    +
    See also
    smaxShareArray()
    +
    +smaxShareField()
    +
    +smaxShareStruct()
    + +

    References smaxShareArray().

    + +
    +
    + +

    ◆ smaxShareArray()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    int smaxShareArray (const char * table,
    const char * key,
    const void * ptr,
    XType type,
    int ndim,
    const int * sizes )
    +
    +

    Share a multidimensional array, such as an int[][][], or float[][], in a single atomic transaction.

    +
    Parameters
    + + + + + + + +
    tableHash table in which to write entry.
    keyVariable name under which the data is stored.
    ptrPointer to the data buffer, such as an int[][][] or float[][].
    typeSMA-X variable type, e.g. X_FLOAT or X_CHARS(40), of the buffer.
    ndimDimensionality of the data (0 <= ndim <= X_MAX_DIMS).
    sizesAn array of ints containing the sizes along each dimension.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized. X_GROUP_INVALID if the table name is invalid. X_NAME_INVALID if the 'key' argument is invalid. X_SIZE_INVALID if ndim or sizes are invalid. X_NULL if the 'value' argument is NULL. X_NO_SERVICE if there was no connection to the Redis server. X_FAILURE if there was an underlying failure.
    +
    See also
    smaxShare()
    + +

    References smaxShareField(), and smaxValuesToString().

    + +
    +
    + +

    ◆ smaxShareBoolean()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxShareBoolean (const char * table,
    const char * key,
    boolean value )
    +
    +

    Shares a single boolean value to SMA-X. All non-zero values are mapped to "1".

    +
    Parameters
    + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    valueA boolean value.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareBooleans()
    + +

    References smaxShareBooleans().

    + +
    +
    + +

    ◆ smaxShareBooleans()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxShareBooleans (const char * table,
    const char * key,
    const boolean * values,
    int n )
    +
    +

    Shares an array of boolean values to SMA-X. All non-zero values are mapped to "1".

    +
    Parameters
    + + + + + +
    tableHash table name.
    keyVariable name under which the data is stored.
    valuesPointer to boolean[] array.
    nNumber of elements in array to share.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareBoolean()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxShareBytes()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxShareBytes (const char * table,
    const char * key,
    const char * values,
    int n )
    +
    +

    Shares a binary sequence to SMA-X.

    +
    Parameters
    + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    valuespointer to the byte buffer.
    nNumber of bytes in buffer to share.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareShorts()
    +
    +smaxShareInts()
    +
    +smaxShareLongs()
    +
    +smaxShareInt()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxShareDouble()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxShareDouble (const char * table,
    const char * key,
    double value )
    +
    +

    Shares a single floating point value to SMA-X.

    +
    Parameters
    + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    valuefloating-point value.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareDoubles()
    +
    +smaxShareFloats()
    + +

    References smaxShareDoubles().

    + +
    +
    + +

    ◆ smaxShareDoubles()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxShareDoubles (const char * table,
    const char * key,
    const double * values,
    int n )
    +
    +

    Shares an array of doubles to SMA-X.

    +
    Parameters
    + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    valuesPointer to double[] array.
    nNumber of elements in array to share.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareDouble()
    +
    +smaxShareFloats()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxShareField()

    + +
    +
    + + + + + + + + + + + +
    int smaxShareField (const char * table,
    const XField * f )
    +
    +

    Share a field object, which may contain any SMA-X data type.

    +
    Parameters
    + + + +
    tableHash table in which to write entry.
    fPointer for XField holding the data to share.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized. X_GROUP_INVALID if the table name is invalid. X_NAME_INVALID if the 'key' argument is invalid. X_SIZE_INVALID if ndim or sizes are invalid. X_NULL if the 'value' argument is NULL. X_NO_SERVICE if there was no connection to the Redis server. X_FAILURE if there was an underlying failure.
    +
    See also
    smaxShare()
    +
    +smaxShareField()
    +
    +smaxShareStruct()
    +
    +xSetField()
    +
    +xGetField()
    + +

    References smaxShareStruct().

    + +
    +
    + +

    ◆ smaxShareFloats()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxShareFloats (const char * table,
    const char * key,
    const float * values,
    int n )
    +
    +

    Shares an array of floats to SMA-X.

    +
    Parameters
    + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    valuesPointer to float[] array.
    nNumber of elements in array to share.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareDouble()
    +
    +smaxShareDoubles()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxShareHex()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxShareHex (const char * table,
    const char * key,
    long long value )
    +
    +

    Shares a single integer value to SMA-X in a hexadecimal representatin.

    +
    Parameters
    + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    valueInteger value.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareInt()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxShareInt()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxShareInt (const char * table,
    const char * key,
    long long value )
    +
    +

    Shares a single integer value to SMA-X.

    +
    Parameters
    + + + + +
    tableHash table name.
    keyVariable name under which the data is stored.
    valueInteger value.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareHex()
    +
    +smaxShareInts()
    + +

    References smaxShareLongs().

    + +
    +
    + +

    ◆ smaxShareInts()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxShareInts (const char * table,
    const char * key,
    const int * values,
    int n )
    +
    +

    Shares an array of long integers to SMA-X.

    +
    Parameters
    + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    valuesPointer to int[] array.
    nNumber of elements in array to share.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareLongs()
    +
    +smaxShareShorts()
    +
    +smaxShareBytes()
    +
    +smaxShareInt()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxShareLongs()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxShareLongs (const char * table,
    const char * key,
    const long long * values,
    int n )
    +
    +

    Shares an array of wide integers to SMA-X.

    +
    Parameters
    + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    valuesPointer to long long[] array.
    nNumber of elements in array to share.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareInts()
    +
    +smaxShareShorts()
    +
    +smaxShareBytes()
    +
    +smaxShareInt()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxShareShorts()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxShareShorts (const char * table,
    const char * key,
    const short * values,
    int n )
    +
    +

    Shares an array of shorts to SMA-X.

    +
    Parameters
    + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    valuesPointer to short[] array.
    nNumber of elements in array to share.
    +
    +
    +
    Returns
    X_SUCCESS(0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareInt()
    +
    +smaxShareBytes()
    +
    +smaxShareInts()
    +
    +smaxShareLongs()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxShareString()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxShareString (const char * table,
    const char * key,
    const char * sValue )
    +
    +

    Shares a single string value to SMA-X.

    +
    Parameters
    + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    sValuePointer to string.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareStrings()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxShareStrings()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxShareStrings (const char * table,
    const char * key,
    const char ** sValues,
    int n )
    +
    +

    Shares an array of strings to SMA-X.

    +
    Parameters
    + + + + + +
    tableThe hash table name.
    keyThe variable name under which the data is stored.
    sValuesPointer to array of string pointers.
    nNumber of elements in array to share.
    +
    +
    +
    Returns
    X_SUCCESS (0), or else an appropriate error code (<0) from smaxShare().
    +
    See also
    smaxShareString()
    + +

    References smaxShare().

    + +
    +
    + +

    ◆ smaxShareStruct()

    + +
    +
    + + + + + + + + + + + +
    int smaxShareStruct (const char * id,
    const XStructure * s )
    +
    +

    Share a structure, and all its data including recursive sub-structures, in a single atromic transaction.

    +
    Parameters
    + + + +
    idStructure's ID, i.e. its own aggregated hash table name.
    sPointer to the structure data.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized. X_GROUP_INVALID if the table name is invalid. X_NAME_INVALID if the 'key' argument is invalid. X_NULL if the 'value' argument is NULL. X_NO_SERVICE if there was no connection to the Redis server. X_FAILURE if there was an underlying failure.
    +
    See also
    smaxShare()
    +
    +smaxShareField()
    +
    +xCreateStruct()
    + +

    References smaxCreateField().

    + +
    +
    + +

    ◆ smaxStringToValues()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    int smaxStringToValues (const char * str,
    void * value,
    XType type,
    int eCount,
    int * pos )
    +
    +

    Deserializes a string to binary values.

    +
    Parameters
    + + + + + + +
    [in]strSerialized ASCII representation of the data (as stored by Redis).
    [out]valuePointer to the buffer that will hold the binary values. The caller is responsible for ensuring the buffer is sufficiently sized for holding the data for the given variable.
    [in]typeShare type, e.g. X_INT. The types X_RAW, X_STRUCT are not supported by this function.
    [in]eCountNumber of elements to retrieve. Ignored for X_STRUCT.
    [out]posParse position, i.e. the number of characters parsed from the input string...
    +
    +
    +
    Returns
    Number of elements successfully parsed, or a negative error code:
                            X_NULL               If the value or str argument is NULL.
    +                        X_TYPE_INVALID       If the type is not supported.
    +                        X_SIZE_INVALID       If size is invalid (e.g. X_RAW, X_STRUCT)
    +                        X_PARSE_ERROR        If the tokens could not be parsed in the format expected
    +
    + +

    References smaxUnpackStrings().

    + +
    +
    + +

    ◆ smaxStringType()

    + +
    +
    + + + + + + + +
    char * smaxStringType (XType type)
    +
    +

    Returns the string type for a given XType argument as a constant expression. For examples X_LONG -> "int64".

    +
    Parameters
    + + +
    typeSMA-X type, e.g. X_FLOAT
    +
    +
    +
    Returns
    Corresponding string type, e.g. "float". (Default is "string" – since typically anything can be represented as strings.)
    +
    See also
    smaxTypeForString()
    + +
    +
    + +

    ◆ smaxSubscribe()

    + +
    +
    + + + + + + + + + + + +
    int smaxSubscribe (const char * table,
    const char * key )
    +
    +

    Subscribes to a specific key(s) in specific group(s). Both the group and key names may contain Redis subscription patterns, e.g. '*' or '?', or bound characters in square-brackets, e.g. '[ab]'. The subscription only enables receiving update notifications from Redis for the specified variable or variables. After subscribing, you can either wait on the subscribed variables to change, or add callback functions to process subscribed variables changes, via smaxAddSubscriber().

    +
    Parameters
    + + + +
    tableVariable group pattern, i.e. hash-table names. (NULL is the same as '*').
    keyVariable name pattern. (if NULL then subscribes only to the table stem).
    +
    +
    +
    Returns
    X_SUCCESS if successfully subscribed to the Redis distribution channel. X_NO_SERVICE if there is no active connection to the Redis server. X_NULL if the channel argument is NULL X_NO_INIT if the SMA-X library was not initialized.
    +
    See also
    smaxUnsubscribe()
    +
    +smaxWaitOnSubscribed()
    +
    +smaxWaitOnSubscribedGroup()
    +
    +smaxWaitOnSubscribedVar()
    +
    +smaxWaitOnAnySubscribed()
    +
    +smaxAddSubscriber()
    + +
    +
    + +

    ◆ smaxSync()

    + +
    +
    + + + + + + + + + + + +
    int smaxSync (XSyncPoint * sync,
    int timeoutMillis )
    +
    +

    Waits for the queue to reach the specified sync point, up to an optional timeout limit.

    +
    Parameters
    + + + +
    syncPointer to a queued synchronization point.
    timeoutMillisAn optional timeout in milliseconds. When set to a positive value The call will be guaranteed to return in the specified interval, whether or not the pipelined reads all succeeded. The return value can be used to check for errors or if the call timed out before all data were collected. If X_TIMEDOUT is returned, smax_end_bulk_pulls() may be called again to allow more time for the queued read operations to complete. 0 or negative timeout values will cause the call to wait indefinitely until reads are complete.
    +
    +
    +
    Returns
    X_SUCCESS (0) if all reads have completed successfully, or the first read error that was enountered (e.g. RM_INVALID_KEY), or: X_TIMEDOUT if the call timed out while still awaiting data for the queued read requests. X_NULL if the SyncPoint argument is NULL, or its mutex/condition field have not been initialized. X_FAILURE if the SyncPoint's mutex has not been initialized.
    +

    or the first pull error encountered in the queue since the current batch began.

    +
    See also
    smaxCreateSyncPoint()
    +
    +smaxWaitQueueComplete()
    + +

    References XSyncPoint::isComplete, XSyncPoint::lock, and XSyncPoint::status.

    + +
    +
    + +

    ◆ smaxTimestamp()

    + +
    +
    + + + + + + + +
    int smaxTimestamp (char * buf)
    +
    +

    Prints the current time into the supplied buffer with subsecond precision.

    +
    Parameters
    + + +
    [out]bufPointer to string buffer, must be at least X_TIMESTAMP_LENGTH in size.
    +
    +
    +
    Returns
    Number of characters printed, not including the terminating '\0', or else an error code (<0) if the buf argument is NULL.
    + +

    References smaxTimeToString().

    + +
    +
    + +

    ◆ smaxTimeToString()

    + +
    +
    + + + + + + + + + + + +
    int smaxTimeToString (const struct timespec * time,
    char * buf )
    +
    + +

    *‍/

    +

    Prints the given UNIX time into the supplied buffer with subsecond precision.

    +
    Parameters
    + + + +
    [in]timePointer to time value.
    [out]bufPointer to string buffer, must be at least X_TIMESTAMP_LENGTH in size.
    +
    +
    +
    Returns
    Number of characters printed, not including the terminating '\0', or else an error code (<0) if the buf argument is NULL.
    + +
    +
    + +

    ◆ smaxTypeForString()

    + +
    +
    + + + + + + + +
    XType smaxTypeForString (const char * type)
    +
    +

    Returns the XType for a given case-sensitive type string. For example "float" -> X_FLOAT. The value "raw" will return X_RAW.

    +
    Parameters
    + + +
    typeString type, e.g. "struct".
    +
    +
    +
    Returns
    Corresponding XType, e.g. X_STRUCT. (The default return value is X_RAW, since all Redis values can be represented as raw strings.)
    +
    See also
    smaxStringType()
    + +
    +
    + +

    ◆ smaxUnpackStrings()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    int smaxUnpackStrings (const char * data,
    int len,
    int count,
    char ** dst )
    +
    +

    Returns an array of dynamically allocated strings from a packed buffer of consecutive 0-terminated or '\r'-separated string elements.

    +
    Parameters
    + + + + + +
    [in]dataPointer to the packed string data buffer.
    [in]lenlength of packed string (excl. termination).
    [in]countNumber of string elements expected. If fewer than that are found in the packed data, then the returned array of pointers will be padded with NULL.
    [out]dstAn array of string pointers (of size 'count') which will point to dynamically allocated string (char*) elements. The array is assumed to be uninitialized, and elements will be allocated as necessary.
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NULL if one of the argument pointers is NULL, or else X_INCOMPLETE if some of the components were too large to unpack (alloc error).
    + +
    +
    + +

    ◆ smaxUnsubscribe()

    + +
    +
    + + + + + + + + + + + +
    int smaxUnsubscribe (const char * table,
    const char * key )
    +
    +

    Unsubscribes from a specific key(s) in specific group(s). Both the group and key names may contain Redis subscription patterns, e.g. '*' or '?', or bound characters in square-brackets, e.g. '[ab]'. Unsubscribing will only stops the delivery of update notifications for the affected varuiables, but does not deactivate the associated callbacks for these added via smaxAddSubscriber(). Therefore you should also call smaxRemovesubscribers() as appropriate to deactivate actions that can no longer get triggered by updates.

    +
    Parameters
    + + + +
    tableVariable group pattern, i.e. structure or hash-table name(s) (NULL is the same as '*').
    keyVariable name pattern. (if NULL then unsubscribes only from the table stem).
    +
    +
    +
    Returns
    X_SUCCESS if successfully unsubscribed to the Redis distribution channel. X_NO_SERVICE if there is no active connection to the Redis server. X_NULL if the channel argument is NULL X_NO_INIT if the SMA-X library was not initialized.
    +
    See also
    smaxSubscribe()
    +
    +smaxRemoveSubscribers()
    + +
    +
    + +

    ◆ smaxValuesToString()

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    char * smaxValuesToString (const void * value,
    XType type,
    int eCount,
    char * trybuf,
    int trylength )
    +
    +

    Serializes binary values into a string representation (for Redis).

    +
    Parameters
    + + + + + + +
    [in]valuePointer to an array of values, or NULL to produce all zeroes. If type is X_STRING value should be a pointer to a char** (array of string pointers), as opposed to X_CHAR(n), which expects a contiguous char* buffer with [n * eCount] length (Note, a char[eCount][n] is equivalent to such a char* buffer).
    [in]typeShare type, e.g. X_DOUBLE. All type except X_STRUCT are supported.
    [in]eCountNumber of elements (ignored for X_RAW).
    [in,out]trybuf(optional) An optional pointer to a buffer that will be used if sufficient (can be NULL).
    [in]trylength(optional) Size of the optional buffer.
    +
    +
    +
    Returns
    The pointer to the string buffer holding the ASCII values. It may be the supplied buffer (if sufficient), the input value (if type is X_RAW) or else a dynamically allocated buffer, or NULL if the key is malformed. If the returned value is neither the input value nor trybuf, then the caller is responsible for calling free() on the dynamically allocated buffer after use.
    + +
    +
    + +

    ◆ smaxWaitOnAnySubscribed()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxWaitOnAnySubscribed (char ** changedTable,
    char ** changedKey,
    int timeout )
    +
    +

    Waits until any variable was pushed on any host, returning both the host and variable name for the updated value. The variable must be already subscribed to with smaxSubscribe(), or else the wait will not receive update notifications.

    +
    Parameters
    + + + + +
    [out]changedTablePointer to the variable that points to the string buffer for the returned table name or NULL. The lease of the buffer is for the call only.
    [out]changedKeyPointer to the variable that points to the string buffer for the returned variable name or NULL. The lease of the buffer is for the call only.
    [in]timeout(s) Timeout value. 0 or negative values result in an indefinite wait.
    +
    +
    +
    Returns
    X_SUCCESS (0) if a variable was pushed on a host. X_NO_INIT if the SMA-X sharing was not initialized via smaxConnect(). X_NO_SERVICE if the connection was broken X_GROUP_INVALID if the buffer for the returned table name is NULL. X_NAME_INVALID if the buffer for the returned variable name is NULL. X_INTERRUPTED if smaxReleaseWaits() was called. X_INCOMPLETE if the wait timed out.
    +
    See also
    smaxSubscribe()
    +
    +smaxWaitOnSubscribed()
    +
    +smaxWaitOnSubscribedGroup()
    +
    +smaxReleaseWaits()
    + +

    References RELEASEID, and smaxIsConnected().

    + +
    +
    + +

    ◆ smaxWaitOnSubscribed()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxWaitOnSubscribed (const char * table,
    const char * key,
    int timeout )
    +
    +

    Waits for a specific pushed entry. There must be an active subscription that includes the specified group & variable, or else the call will block indefinitely.

    +
    Parameters
    + + + + +
    tableHash table name
    keyVariable name to wait on.
    timeout(s) Timeout value. 0 or negative values result in an indefinite wait.
    +
    +
    +
    Returns
    X_SUCCESS (0) if the variable was updated on some host (or owner). X_NO_INIT if the SMA-X sharing was not initialized via smaxConnect(). X_GROUP_INVALID if the 'group' argument is NULL; X_NAME_INVALID if the 'key' argument is NULL. X_REL_PREMATURE if smaxReleaseWaits() was called.
    +
    See also
    smaxSubscribe()
    +
    +smaxWaitOnSubscribed()
    +
    +smaxWaitOnSubscribedGroup()
    +
    +smaxWaitOnSubscribedVar()
    +
    +smaxWaitOnAnySubscribed()
    +
    +smaxReleaseWaits()
    + +
    +
    + +

    ◆ smaxWaitOnSubscribedGroup()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxWaitOnSubscribedGroup (const char * matchTable,
    char ** changedKey,
    int timeout )
    +
    +

    Waits for changes on a specific group. The must be an active subscription including that group, or else the call will block indefinitely.

    +
    Parameters
    + + + + +
    [in]matchTableHash table name (e.g. owner ID) to wait on.
    [out]changedKeyPointer to the string that holds the name of the variable which unblocked the wait or which is set to NULL. The lease of the buffer is for the call only. The caller should copy its content if persistent storage is required.
    [in]timeout(s) Timeout value. 0 or negative values result in an indefinite wait.
    +
    +
    +
    Returns
    X_SUCCESS (0) if a variable was updated on the host. X_NO_INIT if the SMA-X sharing was not initialized via smaxConnect(). X_GROUP_INVALID if the table name to match is invalid. X_REL_PREMATURE if smaxReleaseWaits() was called.
    +
    See also
    smaxSubscribe()
    +
    +smaxWaitOnSubscribedVar()
    +
    +smaxWaitOnSubscribed()
    +
    +smaxWaitOnAnySubscribed()
    +
    +smaxReleaseWaits()
    + +
    +
    + +

    ◆ smaxWaitOnSubscribedVar()

    + +
    +
    + + + + + + + + + + + + + + + + +
    int smaxWaitOnSubscribedVar (const char * matchKey,
    char ** changedTable,
    int timeout )
    +
    +

    Waits for a specific pushed variable from any group/table. There must be an active subscription that includes the specified variable in one or more groups/tables, or else the call will block indefinitely.

    +
    Parameters
    + + + + +
    [in]matchKeyVariable name to wait on.
    [out]changedTablePointer to the string that holds the name of the table which unblocked the wait or which is set to NULL. The lease of the buffer is for the call only. The caller should copy its content if persistent storage is required.
    [in]timeout(s) Timeout value. 0 or negative values result in an indefinite wait.
    +
    +
    +
    Returns
    X_SUCCESS (0) if the variable was updated on some host (or owner). X_NO_INIT if the SMA-X sharing was not initialized via smaxConnect(). X_NAME_INVALID if the 'key' argument is NULL. X_REL_PREMATURE if smaxReleaseWaits() was called.
    +
    See also
    smaxSubscribe()
    +
    +smaxWaitOnSubscribedGroup()
    +
    +smaxWaitOnSubscribed()
    +
    +smaxWaitOnAnySubscribed()
    +
    +smaxReleaseWaits()
    + +
    +
    + +

    ◆ smaxWaitQueueComplete()

    + +
    +
    + + + + + + + +
    int smaxWaitQueueComplete (int timeoutMillis)
    +
    +

    Waits until all queued pull requests have been retrieved from the database, or until the specified timeout it reached.

    +
    Parameters
    + + +
    timeoutMillisAn optional timeout in milliseconds. When set to a positive value The call will be guaranteed to return in the specified interval, whether or not the pipelined reads all succeeded. The return value can be used to check for errors or if the call timed out before all data were collected. If X_TIMEDOUT is returned, smax_end_bulk_pulls() may be called again to allow more time for the queued read operations to complete. 0 or negative timeout values will cause the call to wait indefinitely until reads are complete.
    +
    +
    +
    Returns
    X_SUCCESS (0) if all reads have completed successfully, or the first read error that was enountered (e.g. RM_INVALID_KEY), or: X_TIMEDOUT if the call timed out while still awaiting data for the queued read requests.
    +
    See also
    smaxSync()
    + +

    References XSyncPoint::isComplete, XSyncPoint::lock, smaxSync(), and XSyncPoint::status.

    + +
    +
    + +

    ◆ x2smaxField()

    + +
    +
    + + + + + + + +
    int x2smaxField (XField * f)
    +
    +

    Converts a standard xchange field (with a native value storage) to an SMA-X field with serialized string value storage.

    +
    Parameters
    + + +
    [in,out]fPointer to field to convert
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_NULL if the input field or the serialized value is NULL.
    +
    See also
    smax2xField()
    +
    +x2smaxStruct()
    + +

    References smaxValuesToString(), and x2smaxStruct().

    + +
    +
    + +

    ◆ x2smaxStruct()

    + +
    +
    + + + + + + + +
    int x2smaxStruct (XStructure * s)
    +
    +

    Converts a standard xchange structure (with a native value storage) to an SMA-X structure with serialized string value storage.

    +
    Parameters
    + + +
    sPointer to structure to convert
    +
    +
    +
    Returns
    X_SUCCESS (0) if successful, or X_STRUCT_INVALID if the structure is NULL, or had a NULL substructure. X_NULL if there was a field that could not be converted.
    +
    See also
    smax2xStruct()
    +
    +x2smaxField()
    + +

    References x2smaxField().

    + +
    +
    +
    +
    + + + + diff --git a/apidoc/html/smax_8h.js b/apidoc/html/smax_8h.js new file mode 100644 index 0000000..53bc77e --- /dev/null +++ b/apidoc/html/smax_8h.js @@ -0,0 +1,180 @@ +var smax_8h = +[ + [ "XCoordinateAxis", "structXCoordinateAxis.html", "structXCoordinateAxis" ], + [ "XCoordinateSystem", "structXCoordinateSystem.html", "structXCoordinateSystem" ], + [ "XMessage", "structXMessage.html", "structXMessage" ], + [ "XMeta", "structXMeta.html", "structXMeta" ], + [ "XSyncPoint", "structXSyncPoint.html", "structXSyncPoint" ], + [ "META_COORDS", "smax_8h.html#a6306140d9f65104bc6e0bfd63cbbc2f1", null ], + [ "META_DESCRIPTION", "smax_8h.html#a3cd80ac3dbca64268a52d6bc8b273d82", null ], + [ "META_UNIT", "smax_8h.html#aa1f2f2081a2949053cf74cd4ad47a8d2", null ], + [ "SMAX_DEFAULT_HOSTNAME", "smax_8h.html#a0fe198db49d87d696072c261e49f7cce", null ], + [ "SMAX_DEFAULT_MAX_QUEUED", "smax_8h.html#aeb7304db99c63c3f0a10fca90e74abe4", null ], + [ "SMAX_DEFAULT_PIPELINE_ENABLED", "smax_8h.html#aac2af1cdc522f5e3acc75edf7d41b267", null ], + [ "SMAX_DIMS", "smax_8h.html#a59b5959fb0859d4dbe98408f2cc2f1d0", null ], + [ "SMAX_MSG_DEBUG", "smax_8h.html#a8b3859624653c39bebe617c91567ad0d", null ], + [ "SMAX_MSG_DETAIL", "smax_8h.html#a06ee6433a1353c48c2c8ce5e8fd6631c", null ], + [ "SMAX_MSG_ERROR", "smax_8h.html#aeae00b97b43f8563939cd9ebcfdc4c62", null ], + [ "SMAX_MSG_INFO", "smax_8h.html#a539edc8fa4545dbe7c388e8f0644f6c0", null ], + [ "SMAX_MSG_PROGRESS", "smax_8h.html#a52b656c8731bc8ef9ef83d5307fd157e", null ], + [ "SMAX_MSG_STATUS", "smax_8h.html#a3168f34d2cd8afae9e9f9848ee684597", null ], + [ "SMAX_MSG_WARNING", "smax_8h.html#a007762d6503940a6e287efab02083276", null ], + [ "SMAX_ORIGIN_LENGTH", "smax_8h.html#a012a406ddc842479b2aefaa987e6c591", null ], + [ "SMAX_ORIGINS", "smax_8h.html#a30235420adcb90ff2d2a0f6085a23427", null ], + [ "SMAX_PIPE_READ_TIMEOUT_MILLIS", "smax_8h.html#a38eb97e64eaf65a5273fa6d6ff765a93", null ], + [ "SMAX_READS", "smax_8h.html#ab986e2d3951e64cb3300a62c1f010551", null ], + [ "SMAX_RECONNECT_RETRY_SECONDS", "smax_8h.html#a3e9baa458ae59eb26923d6ce863bf700", null ], + [ "SMAX_RESTORE_QUEUE_ON_RECONNECT", "smax_8h.html#a2f111386ac4b76cd858de99478720b29", null ], + [ "SMAX_SCRIPTS", "smax_8h.html#a23dedcaf9704eed433cf3920af5e5e1c", null ], + [ "SMAX_TIMESTAMPS", "smax_8h.html#ab5e13a0e5a3b57b087a2c875a01317b4", null ], + [ "SMAX_TYPES", "smax_8h.html#a6933f3dab1f1de96cca777d65cdd5c40", null ], + [ "SMAX_UPDATES", "smax_8h.html#a341a9de00cacd431dcd8ac8622b0bf7d", null ], + [ "SMAX_UPDATES_LENGTH", "smax_8h.html#ac59ccff9171d5b4e9545fd1ceef027b8", null ], + [ "SMAX_UPDATES_ROOT", "smax_8h.html#abfefd74fb72fc51e4577d1fa5fa832f4", null ], + [ "SMAX_WRITES", "smax_8h.html#af6088c6c91a1f0089000288f0214f67c", null ], + [ "X_META_INIT", "smax_8h.html#a793fead1eb30470e219192befc88b3c9", null ], + [ "smax2xField", "smax_8h.html#abfe751f22aa718133911ffdee848f64a", null ], + [ "smax2xStruct", "smax_8h.html#a50fef3b0daf40f7de6f52b05abd2963c", null ], + [ "smaxAddConnectHook", "smax_8h.html#ad63c425cc3affdf8bc803c7ff8dd6e30", null ], + [ "smaxAddDefaultMessageProcessor", "smax_8h.html#aa3e777f85e81ffb9b02dc8cc3d124a94", null ], + [ "smaxAddDisconnectHook", "smax_8h.html#a65ae161b28cfe4369709fae1d3ea678c", null ], + [ "smaxAddMessageProcessor", "smax_8h.html#abaa2573fb8e85e8359c8853647c38f2f", null ], + [ "smaxAddSubscriber", "smax_8h.html#a1714cac6dfa55917edecd0028e6da64c", null ], + [ "smaxConnect", "smax_8h.html#a146fb2ed8512919dc91ecad6d08c74d1", null ], + [ "smaxConnectTo", "smax_8h.html#ad960c22b119ff2493a319945a9dd55a5", null ], + [ "smaxCreate1DField", "smax_8h.html#afba357d35d2a1f13d0cf06f5ff708a99", null ], + [ "smaxCreateBooleanField", "smax_8h.html#a13e357c3f20c0799fba6bc6c2a16c520", null ], + [ "smaxCreateCoordinateSystem", "smax_8h.html#a1d977e7e9eb45f9ce6cc338fdde9bd8f", null ], + [ "smaxCreateDoubleField", "smax_8h.html#afa9c9ec0f47236c0c560eee724b809d6", null ], + [ "smaxCreateField", "smax_8h.html#a9871356984c4794a9f9caa3870dc6794", null ], + [ "smaxCreateIntField", "smax_8h.html#afcb9ce5f154eef8eccdb0930ec4d613d", null ], + [ "smaxCreateLongField", "smax_8h.html#a23b55eae1ce68356073ea5b191f915e5", null ], + [ "smaxCreateMeta", "smax_8h.html#a48decaf10195b2f21fa77d8ea9b94fff", null ], + [ "smaxCreateScalarField", "smax_8h.html#a61a3760159e6867cdb55b5995435633c", null ], + [ "smaxCreateStringField", "smax_8h.html#aa5c7661e29f4f1ba62f457c7138f2654", null ], + [ "smaxCreateSyncPoint", "smax_8h.html#a30e2e1eb462ed2274a55016830b9abc1", null ], + [ "smaxDeletePattern", "smax_8h.html#a6c116311d61874554f98332831ad872b", null ], + [ "smaxDestroyCoordinateSystem", "smax_8h.html#a92cf6cd3b3f123e21a1cee437f87126d", null ], + [ "smaxDestroySyncPoint", "smax_8h.html#a97ace8424abf924b8ae0397ae83177f2", null ], + [ "smaxDisconnect", "smax_8h.html#a9d1e6ffa837d3582a8165e326cc44bea", null ], + [ "smaxError", "smax_8h.html#aefcb16af3690ffe9c77224af6b394869", null ], + [ "smaxErrorDescription", "smax_8h.html#a51856e0dc0261f8e44c8635d31d6193c", null ], + [ "smaxGetArrayField", "smax_8h.html#a10525c664231e85f3cd9a592915b8919", null ], + [ "smaxGetBooleanField", "smax_8h.html#a555c133ddd7aee3cf481f9e5e15e3d43", null ], + [ "smaxGetCoordinateAxis", "smax_8h.html#a349dc6fe14a2031d679e29804d82d570", null ], + [ "smaxGetCoordinateSystem", "smax_8h.html#a2920bd71f9d340422e0b1b0db4bb3201", null ], + [ "smaxGetDescription", "smax_8h.html#ad7ef601ffd5fbcae7b2c05be6f6bc302", null ], + [ "smaxGetDoubleField", "smax_8h.html#ab7c45d4512c22c24153763aa9e227b68", null ], + [ "smaxGetHostName", "smax_8h.html#ac704fea3e664905af780d2566e3c74b6", null ], + [ "smaxGetKeys", "smax_8h.html#a2544d1fa602e812004e1d68500024ae0", null ], + [ "smaxGetLazyCached", "smax_8h.html#a42c08f13c70400dc1225d4097342ded0", null ], + [ "smaxGetLazyUpdateCount", "smax_8h.html#aeca4aa02259278b240e4131f7edea816", null ], + [ "smaxGetLongField", "smax_8h.html#a8035211bd1fe17551a1517560b2547c4", null ], + [ "smaxGetMetaCount", "smax_8h.html#ac6d47a508669e4ee215cb72c5366fc52", null ], + [ "smaxGetProgramID", "smax_8h.html#abc07a7599e0bac1be15bbcb6b63d4710", null ], + [ "smaxGetRawField", "smax_8h.html#ada517cdb7737bb38695e2a343123583b", null ], + [ "smaxGetRedis", "smax_8h.html#a533fbe770158afe876a3dafa78ba2195", null ], + [ "smaxGetScriptSHA1", "smax_8h.html#a8ef420555c1ddbbcd9f4213f65b4ca66", null ], + [ "smaxGetServerTime", "smax_8h.html#ae6941b762acbd37c60b012d4157681a8", null ], + [ "smaxGetTime", "smax_8h.html#a2a71d93de952060be0154dd5f0d78496", null ], + [ "smaxGetUnits", "smax_8h.html#aa27e3adeb67f2328a162c80bad433f02", null ], + [ "smaxIsConnected", "smax_8h.html#a95cbb68e3eb751219ab3363c93a4840b", null ], + [ "smaxIsPipelined", "smax_8h.html#af6f57a699b784fc67534cff0abd9573b", null ], + [ "smaxIsResilient", "smax_8h.html#a5f5e00f0fd063ac8e36827c852131358", null ], + [ "smaxIsVerbose", "smax_8h.html#a980232c82ed7ebf5425c60db65f828c0", null ], + [ "smaxKeyCount", "smax_8h.html#a7030106bbe70220c97b1e9e3a4633ff4", null ], + [ "smaxLazyCache", "smax_8h.html#a18027e41c40722011815bc878857e3d0", null ], + [ "smaxLazyEnd", "smax_8h.html#a167a60b494fa9ec5b046f9da796f18b5", null ], + [ "smaxLazyFlush", "smax_8h.html#af3d0cff3f8a6ab745907f4544981fdd1", null ], + [ "smaxLazyPull", "smax_8h.html#ab50222d7bbaa985fd6d004d67b0269ce", null ], + [ "smaxLazyPullChars", "smax_8h.html#a45d5c86c16869e5208b9c5cf688adc53", null ], + [ "smaxLazyPullDouble", "smax_8h.html#a31ed83292a29d69e1c9635b21aae7561", null ], + [ "smaxLazyPullDoubleDefault", "smax_8h.html#ac823bc3c1ee1bdbc4c330366fc246c8e", null ], + [ "smaxLazyPullLong", "smax_8h.html#a03e3bb5c838dc621f8c0ba5fb6fe5f87", null ], + [ "smaxLazyPullString", "smax_8h.html#a38d33bcbf9f2f73adbaf040996279859", null ], + [ "smaxLazyPullStruct", "smax_8h.html#af96429709d1b029a8db74cb7407f9ffb", null ], + [ "smaxParseTime", "smax_8h.html#a2c3c82ba5e7844e9f1b70fb4d51716ef", null ], + [ "smaxPull", "smax_8h.html#afb7eec789669c3d3f416857d3615ace6", null ], + [ "smaxPullDouble", "smax_8h.html#aa143c2385f210cdd772f014939e1411e", null ], + [ "smaxPullDoubleDefault", "smax_8h.html#a1d30cb3f0a48b567657975a104a1088f", null ], + [ "smaxPullDoubles", "smax_8h.html#a6e5df36b7eee3944b1ef07edb7f9647d", null ], + [ "smaxPullInt", "smax_8h.html#a42685e249ca24359b0f3f2a04a99b16b", null ], + [ "smaxPullInts", "smax_8h.html#a8cdf0e4d01eaa160b8c96593ce32f4ff", null ], + [ "smaxPullLong", "smax_8h.html#aebedc01880d4253e74b8bde565de00d5", null ], + [ "smaxPullLongs", "smax_8h.html#a843fa579fa26190335aeebb87be63203", null ], + [ "smaxPullMeta", "smax_8h.html#a0d29e7a895c1d5fdc6258ff7426b3521", null ], + [ "smaxPullRaw", "smax_8h.html#a0de71a90fdf235a8aee084543591244f", null ], + [ "smaxPullString", "smax_8h.html#a41bdf6bb7bcb3f0d3cb1c0657f8da1c5", null ], + [ "smaxPullStrings", "smax_8h.html#abc833f0d89e672507e0baeb146e8776b", null ], + [ "smaxPullStruct", "smax_8h.html#ae6d8bf54e6ca203ea25a066d6e439ae5", null ], + [ "smaxPullTime", "smax_8h.html#a6deedf594f19417bfa11b8f2cef360c4", null ], + [ "smaxPullTypeDimension", "smax_8h.html#ab989b724600841b16125977bcb44ffcc", null ], + [ "smaxPushMeta", "smax_8h.html#aaf4c866eb1cb30dfd70e04604f1aa6cf", null ], + [ "smaxQueue", "smax_8h.html#a2c71427a215e2253d93de24788db338d", null ], + [ "smaxQueueCallback", "smax_8h.html#a06781e13ee30b0530ba3ed2e4436b449", null ], + [ "smaxReconnect", "smax_8h.html#aafc75a2e8b8858b8ff0f16e0e73dbd03", null ], + [ "smaxReleaseWaits", "smax_8h.html#a14bc33c30d27be9e2954ae7831099f1c", null ], + [ "smaxRemoveConnectHook", "smax_8h.html#a4708c3c699781abec237045c48719f3d", null ], + [ "smaxRemoveDisconnectHook", "smax_8h.html#a70cdc3f1bf6b97248b5b8ba6df4dc044", null ], + [ "smaxRemoveMessageProcessor", "smax_8h.html#a1550f0f7aed841d5576d47ec7e62e0c4", null ], + [ "smaxRemoveSubscribers", "smax_8h.html#a77d04f4fbb447f169d40b2a24fa7cf71", null ], + [ "smaxResetMeta", "smax_8h.html#a7ea3483859bf8f7764143b8590af067e", null ], + [ "smaxSendDebug", "smax_8h.html#a6c8e73f27c445dedd5ba4ac5b399f8d1", null ], + [ "smaxSendDetail", "smax_8h.html#a2a0607da9db140f4227524da37b3bf51", null ], + [ "smaxSendError", "smax_8h.html#a7d936da43078b9be469a97a6a4bb82a8", null ], + [ "smaxSendInfo", "smax_8h.html#a6056608a81e52d070dcc0f3ee96579b5", null ], + [ "smaxSendProgress", "smax_8h.html#a0f32699c2148f3b09a48e84b3fa4d036", null ], + [ "smaxSendStatus", "smax_8h.html#a3739383ee6770337b3bb023cfe0cc64c", null ], + [ "smaxSendWarning", "smax_8h.html#a740f4a171334a6aa5d4736c15fc327e4", null ], + [ "smaxSetAuth", "smax_8h.html#a097b12d3bbb43175084b0b0a2f55339c", null ], + [ "smaxSetCoordinateAxis", "smax_8h.html#a5d59620a1646428f41b040d1a0a91554", null ], + [ "smaxSetCoordinateSystem", "smax_8h.html#a04c3b8ea7ff6b8117d2dba9bf9edd52f", null ], + [ "smaxSetDB", "smax_8h.html#a79fba7411b5afa132457a6828ff5ed9f", null ], + [ "smaxSetDescription", "smax_8h.html#adcc70ef29ab29f28068ac57e40497b85", null ], + [ "smaxSetHostName", "smax_8h.html#a886e2ed23987201a9808f1c99806b44a", null ], + [ "smaxSetMaxPendingPulls", "smax_8h.html#a7b7ff182bf54594d796d52e7d6a1a41d", null ], + [ "smaxSetMessageSenderID", "smax_8h.html#af3e8295bb941f68cf3177c79cd5fb4d3", null ], + [ "smaxSetOrigin", "smax_8h.html#a9802443ba0d569c3614f5dcf8b0cfc4b", null ], + [ "smaxSetPipelineConsumer", "smax_8h.html#a542b4c264a49b61a6cd25881290df1d1", null ], + [ "smaxSetPipelined", "smax_8h.html#a8d7a3f57360d8e505baa78e445a53875", null ], + [ "smaxSetResilient", "smax_8h.html#a469095a9a74a8ce5d6bbae347d7194e5", null ], + [ "smaxSetResilientExit", "smax_8h.html#ae638a5b4c82119eea5ef7a0ba2cd40c1", null ], + [ "smaxSetServer", "smax_8h.html#a78cf94f007034f63b609cbe72b8047b0", null ], + [ "smaxSetTcpBuf", "smax_8h.html#ac42ee8e8128aac0695c68660f04fd196", null ], + [ "smaxSetUnits", "smax_8h.html#a23e6627339f6bf58e87150aa9ff0c964", null ], + [ "smaxSetVerbose", "smax_8h.html#ac43709380b9ad92133a22ae0d52d107c", null ], + [ "smaxShare", "smax_8h.html#aee07f085e12283ad96f42c4d77430880", null ], + [ "smaxShareArray", "smax_8h.html#a403f2a3f6186c554cba80ff397ea6a9a", null ], + [ "smaxShareBoolean", "smax_8h.html#a294640494c2d892dfb4944cd9da7729a", null ], + [ "smaxShareBooleans", "smax_8h.html#ad4ddc1226e77667c74dd0c3e0cff56a0", null ], + [ "smaxShareBytes", "smax_8h.html#a9274e66d69bf41bbe291bbadbb619acc", null ], + [ "smaxShareDouble", "smax_8h.html#acfbfd2b9a23305d75e45541c5177e42a", null ], + [ "smaxShareDoubles", "smax_8h.html#a1195017071e3733c0ff9c9f6e704e593", null ], + [ "smaxShareField", "smax_8h.html#a0da1227278e6bc105c7dbdba14fd884a", null ], + [ "smaxShareFloats", "smax_8h.html#ace410207bfb5ba9211dc644f7dd2768d", null ], + [ "smaxShareHex", "smax_8h.html#a9efb328571eb7aac0cec75b55676c4e0", null ], + [ "smaxShareInt", "smax_8h.html#adeb667a3e72acedee7d03eb246b8e1ae", null ], + [ "smaxShareInts", "smax_8h.html#acc2181d635e635e330f6e01b7643dadb", null ], + [ "smaxShareLongs", "smax_8h.html#a179730ae8cc7517c96b3e7efb81411fb", null ], + [ "smaxShareShorts", "smax_8h.html#a007815fcac77e840c851a54f97d575ae", null ], + [ "smaxShareString", "smax_8h.html#a5c9657c01a9b8a324a9a1d318dd18e5b", null ], + [ "smaxShareStrings", "smax_8h.html#a63c421116ca043f2d0899b83d8aa91f9", null ], + [ "smaxShareStruct", "smax_8h.html#ab6a1590c953abc1c37fed841cd3a903a", null ], + [ "smaxStringToValues", "smax_8h.html#af57aab7c00cf249480b8fda660dc0256", null ], + [ "smaxStringType", "smax_8h.html#a8d9d92ad8825d4adad4d6288a5681351", null ], + [ "smaxSubscribe", "smax_8h.html#a53614ba57a594135c13b64a2d89eaa43", null ], + [ "smaxSync", "smax_8h.html#a90a901b9e649c77d29379b8fc31cbefc", null ], + [ "smaxTimestamp", "smax_8h.html#ae56da599747b207813a710efc07dd47d", null ], + [ "smaxTimeToString", "smax_8h.html#a49ca81e757e023205085a23c3aa7e3da", null ], + [ "smaxTypeForString", "smax_8h.html#af6a70e896526629e2130009882a1bff8", null ], + [ "smaxUnpackStrings", "smax_8h.html#a5665cd4f5087ab7a07239c30bc561173", null ], + [ "smaxUnsubscribe", "smax_8h.html#af3a5d7bc565ab7de0ac1dd8fafc93f14", null ], + [ "smaxValuesToString", "smax_8h.html#ae67f864946fbcd880e7b5c98b2f876c5", null ], + [ "smaxWaitOnAnySubscribed", "smax_8h.html#a89db98657eab826392d6099d21fff14c", null ], + [ "smaxWaitOnSubscribed", "smax_8h.html#a0e116b41cf8cfbca058dba8476b5d573", null ], + [ "smaxWaitOnSubscribedGroup", "smax_8h.html#af6cae99a805bf84e98390e0bea2470b7", null ], + [ "smaxWaitOnSubscribedVar", "smax_8h.html#af54b8b5d2e79eda86b3349c3c138331c", null ], + [ "smaxWaitQueueComplete", "smax_8h.html#a065361085eed93188b7fd3ffe3a7eaf5", null ], + [ "x2smaxField", "smax_8h.html#a76bd110891905fe4bdae6628547c50d1", null ], + [ "x2smaxStruct", "smax_8h.html#a65cc6cdad09f861b968e2d492abed977", null ] +]; \ No newline at end of file diff --git a/apidoc/html/smithsonian-logo-55x55.png b/apidoc/html/smithsonian-logo-55x55.png new file mode 100644 index 0000000000000000000000000000000000000000..defb2293e67246d8bd1c3ddfacecc32096220cbb GIT binary patch literal 5834 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 literal 0 HcmV?d00001 diff --git a/apidoc/html/splitbar.png b/apidoc/html/splitbar.png new file mode 100644 index 0000000000000000000000000000000000000000..fbb5e55616c9bd3a16dcf61bbfa95f544cae4db8 GIT binary patch literal 283 zcmeAS@N?(olHy`uVBq!ia0vp^Yzz!63>-{AmhX=Jf@VhhPiD4GOiz; ztsgTAFKFy-X<=nvap=Hd2B`xqasm#Sm!9g~-S<}I`Q3-pxBum>nI3elGBWh=FoeyQF6zWTDs_0rmZ*Y$1B qe|}dv?|t6wXBSlzCXs>uEtHQpwKFn0-n|;=TLw>8KbLh*2~7ZrYH05O literal 0 HcmV?d00001 diff --git a/apidoc/html/splitbard.png b/apidoc/html/splitbard.png new file mode 100644 index 0000000000000000000000000000000000000000..97d9fad1e733d2a95b88e05aeeb0b55000733550 GIT binary patch literal 266 zcmeAS@N?(olHy`uVBq!ia0vp^Yzz!63>-{AmhX=Jf@Vh8*{Y+MO-hM znh6Oi%`6bAau9L!@bS~!@^<5w{ZFDBo~FdV{ob@R_{j5J>-vu;-`@85XN`>(ZqnI)`|a1Nxqi#P|Nfi4`uE>` q>-DCe-Y;4wMvQ4FHedYzn~5P>jdzds3O%6b7(8A5T-G@yGywo?yI-XM literal 0 HcmV?d00001 diff --git a/apidoc/html/structXCoordinateAxis.html b/apidoc/html/structXCoordinateAxis.html new file mode 100644 index 0000000..f55ee8c --- /dev/null +++ b/apidoc/html/structXCoordinateAxis.html @@ -0,0 +1,148 @@ + + + + + + + +smax-clib: XCoordinateAxis Struct Reference + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + +
    +
    smax-clib v0.9 +
    +
    A C/C++ client library for SMA-X
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    + +
    XCoordinateAxis Struct Reference
    +
    +
    + +

    Structure that defines a coordinate axis in an XCoordinateSystem for an SMA-X data array. + More...

    + +

    #include <smax.h>

    + + + + + + + + + + + + + + + + + +

    +Data Fields

    +char * name
     Coordinate name, e.g. "x" or "time".
     
    +double refIndex
     Data index at which the reference coordinate value is defined.
     
    +double refValue
     Reference coordinate value in units set above.
     
    +double step
     Coordinate step between consecutive data, in the units defined above.
     
    +char * unit
     Coordinate unit name, e.g. "GHz" or "ms".
     
    +

    Detailed Description

    +

    Structure that defines a coordinate axis in an XCoordinateSystem for an SMA-X data array.

    +
    See also
    XCoordinateSystem
    +

    The documentation for this struct was generated from the following file: +
    +
    + + + + diff --git a/apidoc/html/structXCoordinateAxis.js b/apidoc/html/structXCoordinateAxis.js new file mode 100644 index 0000000..ec48380 --- /dev/null +++ b/apidoc/html/structXCoordinateAxis.js @@ -0,0 +1,8 @@ +var structXCoordinateAxis = +[ + [ "name", "structXCoordinateAxis.html#a5ac083a645d964373f022d03df4849c8", null ], + [ "refIndex", "structXCoordinateAxis.html#ad191af99a874bc633c0834d247427ea8", null ], + [ "refValue", "structXCoordinateAxis.html#ad56f22fc3fbf9639a29ed9f174c67ec2", null ], + [ "step", "structXCoordinateAxis.html#a4736138d712d9ee570d0652f08a4786a", null ], + [ "unit", "structXCoordinateAxis.html#a5a80171400807274a7fa9c95a104dc78", null ] +]; \ No newline at end of file diff --git a/apidoc/html/structXCoordinateSystem.html b/apidoc/html/structXCoordinateSystem.html new file mode 100644 index 0000000..0a831e6 --- /dev/null +++ b/apidoc/html/structXCoordinateSystem.html @@ -0,0 +1,138 @@ + + + + + + + +smax-clib: XCoordinateSystem Struct Reference + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + +
    +
    smax-clib v0.9 +
    +
    A C/C++ client library for SMA-X
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    + +
    XCoordinateSystem Struct Reference
    +
    +
    + +

    Structure that defines a coordinate system, with one or more XCoordinateAxis. + More...

    + +

    #include <smax.h>

    + + + + + + + + +

    +Data Fields

    +XCoordinateAxisaxis
     Array of coordinate axes, with nAxis size.
     
    +int nAxis
     Number of coordinate axes (i.e. dimension)
     
    +

    Detailed Description

    +

    Structure that defines a coordinate system, with one or more XCoordinateAxis.

    +
    See also
    smaxCreateCoordinateSystem()
    +
    +smaxDestroyCoordinateSystem()
    +

    The documentation for this struct was generated from the following file: +
    +
    + + + + diff --git a/apidoc/html/structXCoordinateSystem.js b/apidoc/html/structXCoordinateSystem.js new file mode 100644 index 0000000..d15c7af --- /dev/null +++ b/apidoc/html/structXCoordinateSystem.js @@ -0,0 +1,5 @@ +var structXCoordinateSystem = +[ + [ "axis", "structXCoordinateSystem.html#a5275f744c5bfc9a13b31a19c7ec5346c", null ], + [ "nAxis", "structXCoordinateSystem.html#a66b674e84aa11d53a5f0763237b764ba", null ] +]; \ No newline at end of file diff --git a/apidoc/html/structXMessage.html b/apidoc/html/structXMessage.html new file mode 100644 index 0000000..78fccfe --- /dev/null +++ b/apidoc/html/structXMessage.html @@ -0,0 +1,147 @@ + + + + + + + +smax-clib: XMessage Struct Reference + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + +
    +
    smax-clib v0.9 +
    +
    A C/C++ client library for SMA-X
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    + +
    XMessage Struct Reference
    +
    +
    + +

    SMA-X program message. + More...

    + +

    #include <smax.h>

    + + + + + + + + + + + + + + + + + +

    +Data Fields

    +char * host
     Host where message originated from.
     
    +char * prog
     Originator program name.
     
    +char * text
     Message body (with timestamp stripped).
     
    +double timestamp
     Message timestamp, if available (otherwise 0.0)
     
    +char * type
     Message type, e.g. "info", "detail", "warning", "error".
     
    +

    Detailed Description

    +

    SMA-X program message.

    +

    The documentation for this struct was generated from the following file: +
    +
    + + + + diff --git a/apidoc/html/structXMessage.js b/apidoc/html/structXMessage.js new file mode 100644 index 0000000..288a1fb --- /dev/null +++ b/apidoc/html/structXMessage.js @@ -0,0 +1,8 @@ +var structXMessage = +[ + [ "host", "structXMessage.html#a1c2046dcb30a629d6d9f45ff8f403f12", null ], + [ "prog", "structXMessage.html#acc6113e98e7cd24d9dcfa520749a5d3f", null ], + [ "text", "structXMessage.html#a5633b1433389cec21ade3811bbe9ca5b", null ], + [ "timestamp", "structXMessage.html#a2c17dfa2b3239f2312e94b9de57a7999", null ], + [ "type", "structXMessage.html#a23506fc4821ab6d9671f3e6222591a96", null ] +]; \ No newline at end of file diff --git a/apidoc/html/structXMeta.html b/apidoc/html/structXMeta.html new file mode 100644 index 0000000..b98b4ff --- /dev/null +++ b/apidoc/html/structXMeta.html @@ -0,0 +1,160 @@ + + + + + + + +smax-clib: XMeta Struct Reference + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + +
    +
    smax-clib v0.9 +
    +
    A C/C++ client library for SMA-X
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    + +
    XMeta Struct Reference
    +
    +
    + +

    SMA-X standard metadata. + More...

    + +

    #include <smax.h>

    + + + + + + + + + + + + + + + + + + + + + + + + + + +

    +Data Fields

    +char origin [SMAX_ORIGIN_LENGTH]
     Host name that last modified.
     
    +int serial
     Number of times the variable was updated.
     
    +int status
     Error code or X_SUCCESS.
     
    +int storeBytes
     Total number of bytes stored.
     
    +int storeDim
     Dimensionality of the data as stored.
     
    +int storeSizes [X_MAX_DIMS]
     Sizes along each dimension of the data as stored.
     
    +XType storeType
     Type of variable as stored.
     
    +struct timespec timestamp
     Timestamp of the last modification.
     
    +

    Detailed Description

    +

    SMA-X standard metadata.

    +
    See also
    smaxDestroyMeta()
    +

    The documentation for this struct was generated from the following file: +
    +
    + + + + diff --git a/apidoc/html/structXMeta.js b/apidoc/html/structXMeta.js new file mode 100644 index 0000000..abaf86a --- /dev/null +++ b/apidoc/html/structXMeta.js @@ -0,0 +1,11 @@ +var structXMeta = +[ + [ "origin", "structXMeta.html#a124de75960ce49e7d4dcbdad9237e128", null ], + [ "serial", "structXMeta.html#a4f4017ce7a39a4da2ed1cf8c4dc7de3f", null ], + [ "status", "structXMeta.html#a6e27f49150e9a14580fb313cc2777e00", null ], + [ "storeBytes", "structXMeta.html#a766b48fdc93d03992939adfa91766703", null ], + [ "storeDim", "structXMeta.html#a16e4b9723516717d3493c46157701520", null ], + [ "storeSizes", "structXMeta.html#adb4556a75a248cce0b72e557c81f8af6", null ], + [ "storeType", "structXMeta.html#ace24d22a3441248636253cdb478de9f7", null ], + [ "timestamp", "structXMeta.html#a2aace03835c4d951b3dee117b328ef87", null ] +]; \ No newline at end of file diff --git a/apidoc/html/structXSyncPoint.html b/apidoc/html/structXSyncPoint.html new file mode 100644 index 0000000..bf5b469 --- /dev/null +++ b/apidoc/html/structXSyncPoint.html @@ -0,0 +1,144 @@ + + + + + + + +smax-clib: XSyncPoint Struct Reference + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + +
    +
    smax-clib v0.9 +
    +
    A C/C++ client library for SMA-X
    +
    +
    + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    + +
    XSyncPoint Struct Reference
    +
    +
    + +

    Synchronization point that can be waited upon when queueing pipelined pulls. + More...

    + +

    #include <smax.h>

    + + + + + + + + + + + +

    +Data Fields

    +pthread_cond_t * isComplete
     Condition variable that is used for the actual wait.
     
    +pthread_mutex_t * lock
     Mutex lock.
     
    +int status
     Synchronization status variable (usually X_INCOMPLETE or X_SUCCESS)
     
    +

    Detailed Description

    +

    Synchronization point that can be waited upon when queueing pipelined pulls.

    +
    See also
    smaxCreateSyncPoint()
    +
    +smaxDestroySyncPoint()
    +
    +smaxSync()
    +

    The documentation for this struct was generated from the following file: +
    +
    + + + + diff --git a/apidoc/html/structXSyncPoint.js b/apidoc/html/structXSyncPoint.js new file mode 100644 index 0000000..11d23da --- /dev/null +++ b/apidoc/html/structXSyncPoint.js @@ -0,0 +1,6 @@ +var structXSyncPoint = +[ + [ "isComplete", "structXSyncPoint.html#a0b9f91194934aba0d7936d18d4bc81cc", null ], + [ "lock", "structXSyncPoint.html#a33586b4184d23f2b8f4df153ec23af13", null ], + [ "status", "structXSyncPoint.html#a6e27f49150e9a14580fb313cc2777e00", null ] +]; \ No newline at end of file diff --git a/apidoc/html/sync_off.png b/apidoc/html/sync_off.png new file mode 100644 index 0000000000000000000000000000000000000000..f8b5a506b2f680ffbd9dff4e5172ceb1fd6c810c GIT binary patch literal 814 zcmV+}1JV46P)gT`Vnx5CltIb0p?DKivbr0VW9;)B&dGC*XGFu>!~28xeDFT!{d(S8-^9cO zKtAV1Otgt+5fsP7d+|ohix=W=058V@Je(1C#IRWh97UfsnD74+X>nh?102OGKwLZ) z7Xc0+AjU<%xFw$2U-|)ixhkF?qH+6mT09ZA^96{C$$f?m;2<7|QS0VdXJ@AsUH|+f zz!A`&&4>?H4}KFD0NhGSN&q|+6chk>DHZpGPXmNR3UCyk&qr@>@3*F=CIC-WRaFcQ z4pLZH2;laMxTFEP-9r-y1V|>6G&eWT08*mX;P{%&kisYG}~SY+LhwzY#c* zNPM#5Y5u zm3{TBtgKL6Tuenp1+ZHd7Z;hCnK@_Pe)dT={X;5OtPjHBFnxV}-`D@_>?{il3jlj) zpz(1{L!hfIo6WMcv}FI}jrL&99$U>+S(fP^P2VnoN8)n=;-KRdV1OzMgW(~8o-!8dxEmB3YoCn=H{kn z0xT*jVrOTETrLOT_NT69E5J|UwKxHA1iqRZc+pCBE8+&g5xJ|4yHB)dLYJ53bATW9 zNc^7fM0+T%i+=zPNjKN8;->wfb>P^qSLWe!O4F^!PXM@O#WkUO3fL|Aj>oqmDIy}F s*+HB!4-yUdubx)oFSAi&yaC+)2e{LxBrP!T_W%F@07*qoM6N<$f|2)jaR2}S literal 0 HcmV?d00001 diff --git a/apidoc/html/sync_on.png b/apidoc/html/sync_on.png new file mode 100644 index 0000000000000000000000000000000000000000..172451a0cfcd647918fb282001bed8084e2a01ad GIT binary patch literal 810 zcmV+_1J(SAP)7i_)2!(~EJ@vB3 z#g@|E%w@rNXkqoDV7s!HwU<)srBEu>7VH{ppJ&LJndwBd^*TI1GIkKZ@k*?UMe#^H18|cM;G#$K&}pFfc${TN{8)ZEY>X z!^0F776Q0AFV1R$KDW~Nd_LmwcwQ(JVt02Jz-DJ>hnAKW5{U#A6%_z(#xy|}V2eN? zz~tm4jg5@}hpMTmVPax}hK2?Jr#?;aleML_wUzPlaobZhH8l|qhlxg`hDanrXQwXi zOu@^_7#$s@qoV_`MWrVA-W;_4{(fSy*k^UEtE)3QY;SKjXh+S>x{xjNJulBlJTfvu zNlD2YGq)!2n13iQF9-N4I(A;K_rt+NkK+E$) z7c5{4ErSmF#>NJVi@Nn^ulo9Wy1ToXot-tx2jJqICeRz*W=t5 z*NJvp{36~09Fs1tYvQuC(L8Xh*VD}5^PO(DE)N0VloA((t|=fJxsJzwMO?Iq5fK$t onS(?VzSGl6{GI94s5gMqC)~uRYhQ>&0ssI207*qoM6N<$f<8Nax&QzG literal 0 HcmV?d00001 diff --git a/apidoc/html/tab_a.png b/apidoc/html/tab_a.png new file mode 100644 index 0000000000000000000000000000000000000000..98b9de2b0828978f0c449081e312f50e03ca95c2 GIT binary patch literal 124 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!QqG<(jv*C{Z|5H5WN_qQPQEsM z-4@BfnI+|JEN6RGc?n8dF|_&RFJHf^YTIjl`})V<|Ni>I Zdtwsf`|6hXmq6nfJYD@<);T3K0RZO4EOr0@ literal 0 HcmV?d00001 diff --git a/apidoc/html/tab_ad.png b/apidoc/html/tab_ad.png new file mode 100644 index 0000000000000000000000000000000000000000..5ae6c5e3178f06210094019d25a7620826254948 GIT binary patch literal 119 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!Qg)s$jv*C{Z|C0TWH8`h_I=d< z&c0xEgvPr90iI*Wxze0n42)mCW4WM}cSUPe_`j$BWf=0_?k#_Re)+3^W}fWc6Bzz% TJNma5XcB{`tDnm{r-UW|<2EVf literal 0 HcmV?d00001 diff --git a/apidoc/html/tab_b.png b/apidoc/html/tab_b.png new file mode 100644 index 0000000000000000000000000000000000000000..eca9b7bc90105cf859fd7ed11bcbd1e3995dfc1e GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!QlXwMjv*C{Z|_=jF(~r5UVP#z zaA*F~*17gh0^zT-+C0tA<~)>pXZGS=_Y|R|o}zOT_imptGdOhnwW4A_^J4{j%dbZ< s3wmm@p83OlV7b5{>y=x*&i!PZ|66kX+T5pNKnoZ=UHx3vIVCg!0C)W~r~m)} literal 0 HcmV?d00001 diff --git a/apidoc/html/tab_bd.png b/apidoc/html/tab_bd.png new file mode 100644 index 0000000000000000000000000000000000000000..8b7647ee0c7d52f00aec0acd2ed4e7d219375f41 GIT binary patch literal 140 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!Qo)`sjv*C{Z||PwWKk4gxVX(* z;K+aW^Uvl#c_AbAY?J1d#g``R-Cp(ns^#&hZcFuKo~rj(qB7S`EM7Ln$?K*1u^(KD pFxBFlX!b7~ZKaUVGG1{kTNV+Ku1O1#xAsJ!4rP xXYPDw&ffSxP0T!E$I0A8yJftV&ksa#C-Z#27n5Ch?xZ1GboQIQo2ML#(k?zX yf6688V-=1rFZQ+vz0zl}&s_Un!f8SAJH|B=Im^HQ<$npZhQZU-&t;ucLK6TxTsY+b literal 0 HcmV?d00001 diff --git a/apidoc/html/tab_s.png b/apidoc/html/tab_s.png new file mode 100644 index 0000000000000000000000000000000000000000..65a5c21b2cee912a361181986732f8251e79e707 GIT binary patch literal 161 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!QW>5ujv*C{Z}0MR9TkvaFWCEj zufV1@-6XYozgI=;>$Xv0XE#LFL`# zB2jqXeBEm&4#s=c7S9vbEli>h1,.sm>li>h2,.sm>li>h3,.sm>li>h4,.sm>li>h5,.sm>li>h6{margin:0;padding:0}.sm ul{display:none}.sm li,.sm a{position:relative}.sm a{display:block}.sm a.disabled{cursor:not-allowed}.sm:after{content:"\00a0";display:block;height:0;font:0/0 serif;clear:both;visibility:hidden;overflow:hidden}.sm,.sm *,.sm *:before,.sm *:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.main-menu-btn{position:relative;display:inline-block;width:36px;height:36px;text-indent:36px;margin-left:8px;white-space:nowrap;overflow:hidden;cursor:pointer;-webkit-tap-highlight-color:rgba(0,0,0,0)}.main-menu-btn-icon,.main-menu-btn-icon:before,.main-menu-btn-icon:after{position:absolute;top:50%;left:2px;height:2px;width:24px;background:var(--nav-menu-button-color);-webkit-transition:all .25s;transition:all .25s}.main-menu-btn-icon:before{content:'';top:-7px;left:0}.main-menu-btn-icon:after{content:'';top:7px;left:0}#main-menu-state:checked ~ .main-menu-btn .main-menu-btn-icon{height:0}#main-menu-state:checked ~ .main-menu-btn .main-menu-btn-icon:before{top:0;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}#main-menu-state:checked ~ .main-menu-btn .main-menu-btn-icon:after{top:0;-webkit-transform:rotate(45deg);transform:rotate(45deg)}#main-menu-state{position:absolute;width:1px;height:1px;margin:-1px;border:0;padding:0;overflow:hidden;clip:rect(1px,1px,1px,1px)}#main-menu-state:not(:checked) ~ #main-menu{display:none}#main-menu-state:checked ~ #main-menu{display:block}@media(min-width:768px){.main-menu-btn{position:absolute;top:-99999px}#main-menu-state:not(:checked) ~ #main-menu{display:block}}.sm-dox{background-image:var(--nav-gradient-image)}.sm-dox a,.sm-dox a:focus,.sm-dox a:hover,.sm-dox a:active{padding:0 12px;padding-right:43px;font-family:var(--font-family-nav);font-size:13px;font-weight:bold;line-height:36px;text-decoration:none;text-shadow:var(--nav-text-normal-shadow);color:var(--nav-text-normal-color);outline:0}.sm-dox a:hover{background-image:var(--nav-gradient-active-image);background-repeat:repeat-x;color:var(--nav-text-hover-color);text-shadow:var(--nav-text-hover-shadow)}.sm-dox a.current{color:#d23600}.sm-dox a.disabled{color:#bbb}.sm-dox a span.sub-arrow{position:absolute;top:50%;margin-top:-14px;left:auto;right:3px;width:28px;height:28px;overflow:hidden;font:bold 12px/28px monospace !important;text-align:center;text-shadow:none;background:var(--nav-menu-toggle-color);-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.sm-dox a span.sub-arrow:before{display:block;content:'+'}.sm-dox a.highlighted span.sub-arrow:before{display:block;content:'-'}.sm-dox>li:first-child>a,.sm-dox>li:first-child>:not(ul) a{-moz-border-radius:5px 5px 0 0;-webkit-border-radius:5px;border-radius:5px 5px 0 0}.sm-dox>li:last-child>a,.sm-dox>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul{-moz-border-radius:0 0 5px 5px;-webkit-border-radius:0;border-radius:0 0 5px 5px}.sm-dox>li:last-child>a.highlighted,.sm-dox>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.sm-dox ul{background:var(--nav-menu-background-color)}.sm-dox ul a,.sm-dox ul a:focus,.sm-dox ul a:hover,.sm-dox ul a:active{font-size:12px;border-left:8px solid transparent;line-height:36px;text-shadow:none;background-color:var(--nav-menu-background-color);background-image:none}.sm-dox ul a:hover{background-image:var(--nav-gradient-active-image);background-repeat:repeat-x;color:var(--nav-text-hover-color);text-shadow:0 1px 1px black}.sm-dox ul ul a,.sm-dox ul ul a:hover,.sm-dox ul ul a:focus,.sm-dox ul ul a:active{border-left:16px solid transparent}.sm-dox ul ul ul a,.sm-dox ul ul ul a:hover,.sm-dox ul ul ul a:focus,.sm-dox ul ul ul a:active{border-left:24px solid transparent}.sm-dox ul ul ul ul a,.sm-dox ul ul ul ul a:hover,.sm-dox ul ul ul ul a:focus,.sm-dox ul ul ul ul a:active{border-left:32px solid transparent}.sm-dox ul ul ul ul ul a,.sm-dox ul ul ul ul ul a:hover,.sm-dox ul ul ul ul ul a:focus,.sm-dox ul ul ul ul ul a:active{border-left:40px solid transparent}@media(min-width:768px){.sm-dox ul{position:absolute;width:12em}.sm-dox li{float:left}.sm-dox.sm-rtl li{float:right}.sm-dox ul li,.sm-dox.sm-rtl ul li,.sm-dox.sm-vertical li{float:none}.sm-dox a{white-space:nowrap}.sm-dox ul a,.sm-dox.sm-vertical a{white-space:normal}.sm-dox .sm-nowrap>li>a,.sm-dox .sm-nowrap>li>:not(ul) a{white-space:nowrap}.sm-dox{padding:0 10px;background-image:var(--nav-gradient-image);line-height:36px}.sm-dox a span.sub-arrow{top:50%;margin-top:-2px;right:12px;width:0;height:0;border-width:4px;border-style:solid dashed dashed dashed;border-color:var(--nav-text-normal-color) transparent transparent transparent;background:transparent;-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.sm-dox a,.sm-dox a:focus,.sm-dox a:active,.sm-dox a:hover,.sm-dox a.highlighted{padding:0 12px;background-image:var(--nav-separator-image);background-repeat:no-repeat;background-position:right;-moz-border-radius:0 !important;-webkit-border-radius:0;border-radius:0 !important}.sm-dox a:hover{background-image:var(--nav-gradient-active-image);background-repeat:repeat-x;color:var(--nav-text-hover-color);text-shadow:var(--nav-text-hover-shadow)}.sm-dox a:hover span.sub-arrow{border-color:var(--nav-text-hover-color) transparent transparent transparent}.sm-dox a.has-submenu{padding-right:24px}.sm-dox li{border-top:0}.sm-dox>li>ul:before,.sm-dox>li>ul:after{content:'';position:absolute;top:-18px;left:30px;width:0;height:0;overflow:hidden;border-width:9px;border-style:dashed dashed solid dashed;border-color:transparent transparent #bbb transparent}.sm-dox>li>ul:after{top:-16px;left:31px;border-width:8px;border-color:transparent transparent var(--nav-menu-background-color) transparent}.sm-dox ul{border:1px solid #bbb;padding:5px 0;background:var(--nav-menu-background-color);-moz-border-radius:5px !important;-webkit-border-radius:5px;border-radius:5px !important;-moz-box-shadow:0 5px 9px rgba(0,0,0,0.2);-webkit-box-shadow:0 5px 9px rgba(0,0,0,0.2);box-shadow:0 5px 9px rgba(0,0,0,0.2)}.sm-dox ul a span.sub-arrow{right:8px;top:50%;margin-top:-5px;border-width:5px;border-color:transparent transparent transparent var(--nav-menu-foreground-color);border-style:dashed dashed dashed solid}.sm-dox ul a,.sm-dox ul a:hover,.sm-dox ul a:focus,.sm-dox ul a:active,.sm-dox ul a.highlighted{color:var(--nav-menu-foreground-color);background-image:none;border:0 !important}.sm-dox ul a:hover{background-image:var(--nav-gradient-active-image);background-repeat:repeat-x;color:var(--nav-text-hover-color);text-shadow:var(--nav-text-hover-shadow)}.sm-dox ul a:hover span.sub-arrow{border-color:transparent transparent transparent var(--nav-text-hover-color)}.sm-dox span.scroll-up,.sm-dox span.scroll-down{position:absolute;display:none;visibility:hidden;overflow:hidden;background:var(--nav-menu-background-color);height:36px}.sm-dox span.scroll-up:hover,.sm-dox span.scroll-down:hover{background:#eee}.sm-dox span.scroll-up:hover span.scroll-up-arrow,.sm-dox span.scroll-up:hover span.scroll-down-arrow{border-color:transparent transparent #d23600 transparent}.sm-dox span.scroll-down:hover span.scroll-down-arrow{border-color:#d23600 transparent transparent transparent}.sm-dox span.scroll-up-arrow,.sm-dox span.scroll-down-arrow{position:absolute;top:0;left:50%;margin-left:-6px;width:0;height:0;overflow:hidden;border-width:6px;border-style:dashed dashed solid dashed;border-color:transparent transparent var(--nav-menu-foreground-color) transparent}.sm-dox span.scroll-down-arrow{top:8px;border-style:solid dashed dashed dashed;border-color:var(--nav-menu-foreground-color) transparent transparent transparent}.sm-dox.sm-rtl a.has-submenu{padding-right:12px;padding-left:24px}.sm-dox.sm-rtl a span.sub-arrow{right:auto;left:12px}.sm-dox.sm-rtl.sm-vertical a.has-submenu{padding:10px 20px}.sm-dox.sm-rtl.sm-vertical a span.sub-arrow{right:auto;left:8px;border-style:dashed solid dashed dashed;border-color:transparent #555 transparent transparent}.sm-dox.sm-rtl>li>ul:before{left:auto;right:30px}.sm-dox.sm-rtl>li>ul:after{left:auto;right:31px}.sm-dox.sm-rtl ul a.has-submenu{padding:10px 20px !important}.sm-dox.sm-rtl ul a span.sub-arrow{right:auto;left:8px;border-style:dashed solid dashed dashed;border-color:transparent #555 transparent transparent}.sm-dox.sm-vertical{padding:10px 0;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.sm-dox.sm-vertical a{padding:10px 20px}.sm-dox.sm-vertical a:hover,.sm-dox.sm-vertical a:focus,.sm-dox.sm-vertical a:active,.sm-dox.sm-vertical a.highlighted{background:#fff}.sm-dox.sm-vertical a.disabled{background-image:var(--nav-gradient-image)}.sm-dox.sm-vertical a span.sub-arrow{right:8px;top:50%;margin-top:-5px;border-width:5px;border-style:dashed dashed dashed solid;border-color:transparent transparent transparent #555}.sm-dox.sm-vertical>li>ul:before,.sm-dox.sm-vertical>li>ul:after{display:none}.sm-dox.sm-vertical ul a{padding:10px 20px}.sm-dox.sm-vertical ul a:hover,.sm-dox.sm-vertical ul a:focus,.sm-dox.sm-vertical ul a:active,.sm-dox.sm-vertical ul a.highlighted{background:#eee}.sm-dox.sm-vertical ul a.disabled{background:var(--nav-menu-background-color)}} \ No newline at end of file diff --git a/apidoc/html/toc.xml b/apidoc/html/toc.xml new file mode 100644 index 0000000..1e0e6c0 --- /dev/null +++ b/apidoc/html/toc.xml @@ -0,0 +1,490 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apidoc/man/man3/XCoordinateAxis.3 b/apidoc/man/man3/XCoordinateAxis.3 new file mode 100644 index 0000000..89cdc65 --- /dev/null +++ b/apidoc/man/man3/XCoordinateAxis.3 @@ -0,0 +1,51 @@ +.TH "XCoordinateAxis" 3 "Version v0.9" "smax-clib" \" -*- nroff -*- +.ad l +.nh +.SH NAME +XCoordinateAxis \- Structure that defines a coordinate axis in an \fBXCoordinateSystem\fP for an SMA-X data array\&. + +.SH SYNOPSIS +.br +.PP +.PP +\fR#include \fP +.SS "Data Fields" + +.in +1c +.ti -1c +.RI "char * \fBname\fP" +.br +.RI "Coordinate name, e\&.g\&. 'x' or 'time'\&. " +.ti -1c +.RI "double \fBrefIndex\fP" +.br +.RI "Data index at which the reference coordinate value is defined\&. " +.ti -1c +.RI "double \fBrefValue\fP" +.br +.RI "Reference coordinate value in units set above\&. " +.ti -1c +.RI "double \fBstep\fP" +.br +.RI "Coordinate step between consecutive data, in the units defined above\&. " +.ti -1c +.RI "char * \fBunit\fP" +.br +.RI "Coordinate unit name, e\&.g\&. 'GHz' or 'ms'\&. " +.in -1c +.SH "Detailed Description" +.PP +Structure that defines a coordinate axis in an \fBXCoordinateSystem\fP for an SMA-X data array\&. + + +.PP +\fBSee also\fP +.RS 4 +\fBXCoordinateSystem\fP +.RE +.PP + + +.SH "Author" +.PP +Generated automatically by Doxygen for smax-clib from the source code\&. diff --git a/apidoc/man/man3/XCoordinateSystem.3 b/apidoc/man/man3/XCoordinateSystem.3 new file mode 100644 index 0000000..e2e7ee8 --- /dev/null +++ b/apidoc/man/man3/XCoordinateSystem.3 @@ -0,0 +1,41 @@ +.TH "XCoordinateSystem" 3 "Version v0.9" "smax-clib" \" -*- nroff -*- +.ad l +.nh +.SH NAME +XCoordinateSystem \- Structure that defines a coordinate system, with one or more \fBXCoordinateAxis\fP\&. + +.SH SYNOPSIS +.br +.PP +.PP +\fR#include \fP +.SS "Data Fields" + +.in +1c +.ti -1c +.RI "\fBXCoordinateAxis\fP * \fBaxis\fP" +.br +.RI "Array of coordinate axes, with nAxis size\&. " +.ti -1c +.RI "int \fBnAxis\fP" +.br +.RI "Number of coordinate axes (i\&.e\&. dimension) " +.in -1c +.SH "Detailed Description" +.PP +Structure that defines a coordinate system, with one or more \fBXCoordinateAxis\fP\&. + + +.PP +\fBSee also\fP +.RS 4 +\fBsmaxCreateCoordinateSystem()\fP +.PP +\fBsmaxDestroyCoordinateSystem()\fP +.RE +.PP + + +.SH "Author" +.PP +Generated automatically by Doxygen for smax-clib from the source code\&. diff --git a/apidoc/man/man3/XMessage.3 b/apidoc/man/man3/XMessage.3 new file mode 100644 index 0000000..8a41d0d --- /dev/null +++ b/apidoc/man/man3/XMessage.3 @@ -0,0 +1,42 @@ +.TH "XMessage" 3 "Version v0.9" "smax-clib" \" -*- nroff -*- +.ad l +.nh +.SH NAME +XMessage \- SMA-X program message\&. + +.SH SYNOPSIS +.br +.PP +.PP +\fR#include \fP +.SS "Data Fields" + +.in +1c +.ti -1c +.RI "char * \fBhost\fP" +.br +.RI "Host where message originated from\&. " +.ti -1c +.RI "char * \fBprog\fP" +.br +.RI "Originator program name\&. " +.ti -1c +.RI "char * \fBtext\fP" +.br +.RI "Message body (with timestamp stripped)\&. " +.ti -1c +.RI "double \fBtimestamp\fP" +.br +.RI "Message timestamp, if available (otherwise 0\&.0) " +.ti -1c +.RI "char * \fBtype\fP" +.br +.RI "Message type, e\&.g\&. 'info', 'detail', 'warning', 'error'\&. " +.in -1c +.SH "Detailed Description" +.PP +SMA-X program message\&. + +.SH "Author" +.PP +Generated automatically by Doxygen for smax-clib from the source code\&. diff --git a/apidoc/man/man3/XMeta.3 b/apidoc/man/man3/XMeta.3 new file mode 100644 index 0000000..afc724a --- /dev/null +++ b/apidoc/man/man3/XMeta.3 @@ -0,0 +1,63 @@ +.TH "XMeta" 3 "Version v0.9" "smax-clib" \" -*- nroff -*- +.ad l +.nh +.SH NAME +XMeta \- SMA-X standard metadata\&. + +.SH SYNOPSIS +.br +.PP +.PP +\fR#include \fP +.SS "Data Fields" + +.in +1c +.ti -1c +.RI "char \fBorigin\fP [\fBSMAX_ORIGIN_LENGTH\fP]" +.br +.RI "Host name that last modified\&. " +.ti -1c +.RI "int \fBserial\fP" +.br +.RI "Number of times the variable was updated\&. " +.ti -1c +.RI "int \fBstatus\fP" +.br +.RI "Error code or X_SUCCESS\&. " +.ti -1c +.RI "int \fBstoreBytes\fP" +.br +.RI "Total number of bytes stored\&. " +.ti -1c +.RI "int \fBstoreDim\fP" +.br +.RI "Dimensionality of the data as stored\&. " +.ti -1c +.RI "int \fBstoreSizes\fP [X_MAX_DIMS]" +.br +.RI "Sizes along each dimension of the data as stored\&. " +.ti -1c +.RI "XType \fBstoreType\fP" +.br +.RI "Type of variable as stored\&. " +.ti -1c +.RI "struct timespec \fBtimestamp\fP" +.br +.RI "Timestamp of the last modification\&. " +.in -1c +.SH "Detailed Description" +.PP +SMA-X standard metadata\&. + + +.PP +\fBSee also\fP +.RS 4 +smaxDestroyMeta() +.RE +.PP + + +.SH "Author" +.PP +Generated automatically by Doxygen for smax-clib from the source code\&. diff --git a/apidoc/man/man3/XSyncPoint.3 b/apidoc/man/man3/XSyncPoint.3 new file mode 100644 index 0000000..3507ad0 --- /dev/null +++ b/apidoc/man/man3/XSyncPoint.3 @@ -0,0 +1,47 @@ +.TH "XSyncPoint" 3 "Version v0.9" "smax-clib" \" -*- nroff -*- +.ad l +.nh +.SH NAME +XSyncPoint \- Synchronization point that can be waited upon when queueing pipelined pulls\&. + +.SH SYNOPSIS +.br +.PP +.PP +\fR#include \fP +.SS "Data Fields" + +.in +1c +.ti -1c +.RI "pthread_cond_t * \fBisComplete\fP" +.br +.RI "Condition variable that is used for the actual wait\&. " +.ti -1c +.RI "pthread_mutex_t * \fBlock\fP" +.br +.RI "Mutex lock\&. " +.ti -1c +.RI "int \fBstatus\fP" +.br +.RI "Synchronization status variable (usually X_INCOMPLETE or X_SUCCESS) " +.in -1c +.SH "Detailed Description" +.PP +Synchronization point that can be waited upon when queueing pipelined pulls\&. + + +.PP +\fBSee also\fP +.RS 4 +\fBsmaxCreateSyncPoint()\fP +.PP +\fBsmaxDestroySyncPoint()\fP +.PP +\fBsmaxSync()\fP +.RE +.PP + + +.SH "Author" +.PP +Generated automatically by Doxygen for smax-clib from the source code\&. diff --git a/apidoc/man/man3/md_CHANGELOG.3 b/apidoc/man/man3/md_CHANGELOG.3 new file mode 100644 index 0000000..ec2ed86 --- /dev/null +++ b/apidoc/man/man3/md_CHANGELOG.3 @@ -0,0 +1,12 @@ +.TH "md_CHANGELOG" 3 "Version v0.9" "smax-clib" \" -*- nroff -*- +.ad l +.nh +.SH NAME +md_CHANGELOG \- Changelog +.PP + All notable changes to the \fRSmithsonian/redisx\fP library will be documented in this file\&. +.PP +The format is based on \fRKeep a Changelog\fP, and this project adheres to \fRSemantic Versioning\fP\&. +.SH "[Unreleased]" +.PP +Initial public release\&. diff --git a/apidoc/man/man3/md_CONTRIBUTING.3 b/apidoc/man/man3/md_CONTRIBUTING.3 new file mode 100644 index 0000000..23ae1ea --- /dev/null +++ b/apidoc/man/man3/md_CONTRIBUTING.3 @@ -0,0 +1,27 @@ +.TH "md_CONTRIBUTING" 3 "Version v0.9" "smax-clib" \" -*- nroff -*- +.ad l +.nh +.SH NAME +md_CONTRIBUTING \- Contributing to RedisX +.PP + +.PP +The \fISMA-X C/C++\fP library is for everyone\&. And, it is developers like you who can make it better\&. Whether there is a nagging issue you would like to fix, or a new feature you'd like to see, you can make a difference yourself\&. Make this project a little bit your own, by submitting pull requests with fixes and enhancement\&. When you are ready, here are the typical steps for contributing to the project: +.PP +.IP "1." 4 +Old or new \fBIssue\fP? Whether you just found a bug, or you are missing a much needed feature, start by checking open (and closed) \fRIssues\fP\&. If an existing issue seems like a good match to yours, feel free to speak up, comment, or to offer help in resolving it\&. If you find no issues that match, go ahead and create a new one\&. +.IP "2." 4 +\fBFork\fP\&. Is it something you'd like to help resolve? Great! You should start by creating your own fork of the repository so you can work freely on your solution\&. I recommend that you place your work on a branch of your fork, which is named either after the issue number, e\&.g\&. \fRissue-192\fP, or some other descriptive name, such as \fRsentinel-support\fP\&. +.IP "3." 4 +\fBDevelop\fP\&. Experiment on your fork/branch freely\&. If you run into a dead-end, you can always abandon it (which is why branches are great) and start anew\&. You can run \fRmake all\fP to ensure that all components of the package and its API documentation are also in order\&. Remember to synchronize your \fRmain\fP branch by fetching changes from upstream every once in a while, and merging them into your development branch\&. Don't forget to: +.IP " \(bu" 4 +Add \fBdoxygen\fP markup your new code\&. You can keep it sweet and simple, but make sure it properly explains your globally exposed functions, their arguments and return values\&. You should also cross-reference other functions / constants that are similar, related, or relevant to what you just added\&. +.PP + +.IP "4." 4 +\fBPull Request\fP\&. Once you feel your work can be integrated, create a pull request from your fork/branch\&. You can do that easily from the github page of your fork/branch directly\&. In the pull request, provide a concise description of what you added or changed\&. Your pull request will be reviewed\&. You may get some feedback at this point, and maybe there will be discussions about possible improvements or regressions etc\&. It's a good thing too, and your changes will likely end up with added polish as a result\&. You can be all the more proud of it in the end! +.IP "5." 4 +If all goes well, your pull-request will get merged, and will be included in the upcoming release of \fIsmax-clib\fP\&. Congratulations for your excellent work, and many thanks for dedicating some of your time for making this library a little bit better\&. There will be many who will appreciate it\&. :-) +.PP +.PP +If at any point you have questions, or need feedback, don't be afraid to ask\&. You can put your questions into the issue you found or created, or your pull-request, or as a Q&A in \fRDiscussions\fP\&. diff --git a/apidoc/man/man3/smax-easy.c.3 b/apidoc/man/man3/smax-easy.c.3 new file mode 100644 index 0000000..ff08437 --- /dev/null +++ b/apidoc/man/man3/smax-easy.c.3 @@ -0,0 +1,1203 @@ +.TH "src/smax-easy.c" 3 "Version v0.9" "smax-clib" \" -*- nroff -*- +.ad l +.nh +.SH NAME +src/smax-easy.c \- A set of functions for simplified access to SMA-X for specific variable types\&. + +.SH SYNOPSIS +.br +.PP +.SS "Functions" + +.in +1c +.ti -1c +.RI "XField * \fBsmaxCreate1DField\fP (const char *name, XType type, int size, const void *value)" +.br +.ti -1c +.RI "XField * \fBsmaxCreateBooleanField\fP (const char *name, boolean value)" +.br +.ti -1c +.RI "XField * \fBsmaxCreateDoubleField\fP (const char *name, double value)" +.br +.ti -1c +.RI "XField * \fBsmaxCreateIntField\fP (const char *name, int value)" +.br +.ti -1c +.RI "XField * \fBsmaxCreateLongField\fP (const char *name, long long value)" +.br +.ti -1c +.RI "XField * \fBsmaxCreateScalarField\fP (const char *name, XType type, const void *value)" +.br +.ti -1c +.RI "XField * \fBsmaxCreateStringField\fP (const char *name, const char *value)" +.br +.ti -1c +.RI "int \fBsmaxGetArrayField\fP (const XStructure *s, const char *name, void *dst, XType type, int count)" +.br +.ti -1c +.RI "boolean \fBsmaxGetBooleanField\fP (const XStructure *s, const char *name, boolean defaultValue)" +.br +.ti -1c +.RI "double \fBsmaxGetDoubleField\fP (const XStructure *s, const char *name, double defaultValue)" +.br +.ti -1c +.RI "long long \fBsmaxGetLongField\fP (const XStructure *s, const char *name, long long defaultValue)" +.br +.ti -1c +.RI "char * \fBsmaxGetRawField\fP (const XStructure *s, const char *name, char *defaultValue)" +.br +.ti -1c +.RI "double \fBsmaxPullDouble\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "double \fBsmaxPullDoubleDefault\fP (const char *table, const char *key, double defaultValue)" +.br +.ti -1c +.RI "double * \fBsmaxPullDoubles\fP (const char *table, const char *key, \fBXMeta\fP *meta, int *n)" +.br +.ti -1c +.RI "int \fBsmaxPullInt\fP (const char *table, const char *key, int defaultValue)" +.br +.ti -1c +.RI "int * \fBsmaxPullInts\fP (const char *table, const char *key, \fBXMeta\fP *meta, int *n)" +.br +.ti -1c +.RI "long long \fBsmaxPullLong\fP (const char *table, const char *key, long long defaultValue)" +.br +.ti -1c +.RI "long long * \fBsmaxPullLongs\fP (const char *table, const char *key, \fBXMeta\fP *meta, int *n)" +.br +.ti -1c +.RI "char * \fBsmaxPullRaw\fP (const char *table, const char *key, \fBXMeta\fP *meta, int *status)" +.br +.ti -1c +.RI "char * \fBsmaxPullString\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "char ** \fBsmaxPullStrings\fP (const char *table, const char *key, \fBXMeta\fP *meta, int *n)" +.br +.ti -1c +.RI "XStructure * \fBsmaxPullStruct\fP (const char *id, \fBXMeta\fP *meta, int *status)" +.br +.ti -1c +.RI "int \fBsmaxShareBoolean\fP (const char *table, const char *key, boolean value)" +.br +.ti -1c +.RI "int \fBsmaxShareBooleans\fP (const char *table, const char *key, const boolean *values, int n)" +.br +.ti -1c +.RI "int \fBsmaxShareBytes\fP (const char *table, const char *key, const char *values, int n)" +.br +.ti -1c +.RI "int \fBsmaxShareDouble\fP (const char *table, const char *key, double value)" +.br +.ti -1c +.RI "int \fBsmaxShareDoubles\fP (const char *table, const char *key, const double *values, int n)" +.br +.ti -1c +.RI "int \fBsmaxShareFloats\fP (const char *table, const char *key, const float *values, int n)" +.br +.ti -1c +.RI "int \fBsmaxShareHex\fP (const char *table, const char *key, long long value)" +.br +.ti -1c +.RI "int \fBsmaxShareInt\fP (const char *table, const char *key, long long value)" +.br +.ti -1c +.RI "int \fBsmaxShareInts\fP (const char *table, const char *key, const int *values, int n)" +.br +.ti -1c +.RI "int \fBsmaxShareLongs\fP (const char *table, const char *key, const long long *values, int n)" +.br +.ti -1c +.RI "int \fBsmaxShareShorts\fP (const char *table, const char *key, const short *values, int n)" +.br +.ti -1c +.RI "int \fBsmaxShareString\fP (const char *table, const char *key, const char *sValue)" +.br +.ti -1c +.RI "int \fBsmaxShareStrings\fP (const char *table, const char *key, const char **sValues, int n)" +.br +.ti -1c +.RI "int \fBsmaxWaitOnSubscribed\fP (const char *table, const char *key, int timeout)" +.br +.ti -1c +.RI "int \fBsmaxWaitOnSubscribedGroup\fP (const char *matchTable, char **changedKey, int timeout)" +.br +.ti -1c +.RI "int \fBsmaxWaitOnSubscribedVar\fP (const char *matchKey, char **changedTable, int timeout)" +.br +.in -1c +.SH "Detailed Description" +.PP +A set of functions for simplified access to SMA-X for specific variable types\&. + + +.PP +\fBDate\fP +.RS 4 +Apr 6, 2019 +.RE +.PP +\fBAuthor\fP +.RS 4 +Attila Kovacs +.RE +.PP + +.SH "Function Documentation" +.PP +.SS "XField * smaxCreate1DField (const char * name, XType type, int size, const void * value)" +Creates a field for 1-D array of a given name and type using specified native values\&. It is like \fRxCreate1DField()\fP except that the field is created in serialized form\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP Field name +.br +\fItype\fP Storage type, e\&.g\&. X_INT\&. +.br +\fIsize\fP Array size\&. +.br +\fIvalue\fP Pointer to the native array in memory\&. +.RE +.PP +\fBReturns\fP +.RS 4 +A newly created field with the supplied data, or NULL if there was an error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xSetField() +.RE +.PP + +.PP +References \fBsmaxCreateField()\fP\&. +.SS "XField * smaxCreateBooleanField (const char * name, boolean value)" +Creates a field holding a single boolean value\&. It is like \fRxCreateBooleanField()\fP except that the field is created in serialized form\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP Field name +.br +\fIvalue\fP Associated value +.RE +.PP +\fBReturns\fP +.RS 4 +A newly created field with the supplied data, or NULL if there was an error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xSetField() +.RE +.PP + +.PP +References \fBsmaxCreateScalarField()\fP\&. +.SS "XField * smaxCreateDoubleField (const char * name, double value)" +Creates a field holding a single double-precision value\&. It is like \fRxCreateDoubleField()\fP except that the field is created in serialized form\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP Field name +.br +\fIvalue\fP Associated value +.RE +.PP +\fBReturns\fP +.RS 4 +A newly created field with the supplied data, or NULL if there was an error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xSetField() +.RE +.PP + +.PP +References \fBsmaxCreateScalarField()\fP\&. +.SS "XField * smaxCreateIntField (const char * name, int value)" +Creates a field holding a single integer value\&. It is like \fRxCreateIntField()\fP except that the field is created in serialized form\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP Field name +.br +\fIvalue\fP Associated value +.RE +.PP +\fBReturns\fP +.RS 4 +A newly created field with the supplied data, or NULL if there was an error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xSetField() +.RE +.PP + +.PP +References \fBsmaxCreateScalarField()\fP\&. +.SS "XField * smaxCreateLongField (const char * name, long long value)" +Creates a field holding a single wide (64-bit) integer value\&. It is like \fRxCreateLongField()\fP except that the field is created in serialized form\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP Field name +.br +\fIvalue\fP Associated value +.RE +.PP +\fBReturns\fP +.RS 4 +A newly created field with the supplied data, or NULL if there was an error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xSetField() +.RE +.PP + +.PP +References \fBsmaxCreateScalarField()\fP\&. +.SS "XField * smaxCreateScalarField (const char * name, XType type, const void * value)" +Creates a scalar field of a given name and type using the specified native value\&. It is like \fRxCreateScalarField()\fP except that the field is created in serialized form\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP Field name +.br +\fItype\fP Storage type, e\&.g\&. X_INT\&. +.br +\fIvalue\fP Pointer to the native data location in memory\&. +.RE +.PP +\fBReturns\fP +.RS 4 +A newly created scalar field with the supplied data, or NULL if there was an error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xSetField() +.RE +.PP + +.PP +References \fBsmaxCreate1DField()\fP\&. +.SS "XField * smaxCreateStringField (const char * name, const char * value)" +Creates a field holding a single string value\&. It is like \fRxCreateStringField()\fP except that the field is created in serialized form\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP Field name +.br +\fIvalue\fP Associated value +.RE +.PP +\fBReturns\fP +.RS 4 +A newly created field referencing the supplied string, or NULL if there was an error\&. +.RE +.PP + +.PP +References \fBsmaxCreateScalarField()\fP\&. +.SS "int smaxGetArrayField (const XStructure * s, const char * name, void * dst, XType type, int count)" +Gets the data of an SMA-X structure field as an array of values of the specified type and element count\&. The field's data will be truncated or padded with zeroes to provide the requested element count always\&. +.PP +\fBParameters\fP +.RS 4 +\fIs\fP Pointer to SMA-X structure +.br +\fIname\fP Field name +.br +\fIdst\fP Array to return values in\&. +.br +\fItype\fP Type of data\&. +.br +\fIcount\fP Number of elements in return array\&. The field data will be truncated or padded as necessary\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_STRUCT_INVALID if the input structure is NULL, X_NULL if dst is NULL, X_SIZE_INVALID if n is 0 or negative, X_NAME_INVALID if the structure does not have a field by the specified name, or else an error returned by smaxStringtoValues()\&. +.RE +.PP + +.PP +References \fBsmaxStringToValues()\fP\&. +.SS "boolean smaxGetBooleanField (const XStructure * s, const char * name, boolean defaultValue)" +Returns the first value in a structure's field as an integer, or the specified default value if there is no such field in the structure, or the content cannot be parse into an integer\&. +.PP +\fBParameters\fP +.RS 4 +\fIs\fP Pointer to the XStructure\&. +.br +\fIname\fP Field name +.br +\fIdefaultValue\fP Value to return if no corresponding integer field value\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The (first) field value as a long long, or the default value if there is no such field\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xGetField() +.RE +.PP + +.SS "double smaxGetDoubleField (const XStructure * s, const char * name, double defaultValue)" +Returns the first value in a structure's field as a double precision float, or the specified default value if there is no such field in the structure, or the content cannot be parse into an double\&. +.PP +\fBParameters\fP +.RS 4 +\fIs\fP Pointer to the XStructure\&. +.br +\fIname\fP Field name +.br +\fIdefaultValue\fP Value to return if no corresponding integer field value\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The (first) field value as a double, or the specified default if there is no such field\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xGetField() +.RE +.PP + +.SS "long long smaxGetLongField (const XStructure * s, const char * name, long long defaultValue)" +Returns the first value in a structure's field as an integer, or the specified default value if there is no such field in the structure, or the content cannot be parse into an integer\&. +.PP +\fBParameters\fP +.RS 4 +\fIs\fP Pointer to the XStructure\&. +.br +\fIname\fP Field name +.br +\fIdefaultValue\fP Value to return if no corresponding integer field value\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The (first) field value as a long long, or the default value if there is no such field\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xGetField() +.RE +.PP + +.SS "char * smaxGetRawField (const XStructure * s, const char * name, char * defaultValue)" +Returns the string value in a structure's field, or the specified default value if there is no such field in the structure\&. +.PP +\fBParameters\fP +.RS 4 +\fIs\fP Pointer to the XStructure\&. +.br +\fIname\fP Field name +.br +\fIdefaultValue\fP Value to return if no corresponding integer field value\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The field's string (raw) value, or the specified default if there is no such field\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xGetField() +.RE +.PP + +.SS "double smaxPullDouble (const char * table, const char * key)" +Returns a single floating-point value for a given SMA-X variable, or a NAN if the value could not be retrieved\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The floating-point value stored in SMA-X, or NAN if the value could not be retrieved\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyPullDouble()\fP +.PP +\fBsmaxPullDoubleDefault()\fP +.RE +.PP + +.PP +References \fBsmaxPullDoubleDefault()\fP\&. +.SS "double smaxPullDoubleDefault (const char * table, const char * key, double defaultValue)" +Returns a single floating-point value for a given SMA-X variable, or a specified default value if the SMA-X value could not be retrieved\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.br +\fIdefaultValue\fP The value to return in case of an error\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The floating-point value stored in SMA-X, or the specified default if the value could not be retrieved\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyPullDoubleDefault()\fP +.PP +\fBsmaxPullDouble()\fP +.RE +.PP + +.PP +References \fBsmaxPull()\fP\&. +.SS "double * smaxPullDoubles (const char * table, const char * key, \fBXMeta\fP * meta, int * n)" +Returns a dynamically allocated array of doubles stored in an SMA-X variable\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fImeta\fP (optional) Pointer to metadata to be filled or NULL if not required\&. +.br +\fIn\fP Pointer to which the number of double is returned (if *n > 0) or else an error code\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Pointer to C double[] array containing *n elements, or NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxPullDouble()\fP +.PP +smaxPullFloats() +.RE +.PP + +.SS "int smaxPullInt (const char * table, const char * key, int defaultValue)" +Returns a single integer value for a given SMA-X variable, or a default value if the value could not be retrieved\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIdefaultValue\fP The value to return in case of an error\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The integer value stored in SMA-X, or the specified default if the value could not be retrieved\&. +.RE +.PP +\fBSee also\fP +.RS 4 +smaxLazyPullInt() +.PP +\fBsmaxPullInts()\fP +.PP +smaPullLong() +.RE +.PP + +.PP +References \fBsmaxPull()\fP\&. +.SS "int * smaxPullInts (const char * table, const char * key, \fBXMeta\fP * meta, int * n)" +Returns a dynamically allocated array of integers stored in an SMA-X variable\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fImeta\fP (optional) Pointer to metadata to be filled or NULL if not required\&. +.br +\fIn\fP Pointer to which the number of integers is returned (if *n > 0) or else an error code\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Pointer to C int[] array containing *n elements, or NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +smaxPullShorts() +.PP +\fBsmaxPullLongs()\fP +.PP +\fBsmaxPullInt()\fP +.RE +.PP + +.SS "long long smaxPullLong (const char * table, const char * key, long long defaultValue)" +Returns a single integer value for a given SMA-X variable, or a default value if the value could not be retrieved\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIdefaultValue\fP The value to return in case of an error\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The integer value stored in SMA-X, or the specified default if the value could not be retrieved\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyPullLong()\fP +.PP +\fBsmaxPullLongs()\fP +.PP +\fBsmaxPullInt()\fP +.RE +.PP + +.PP +References \fBsmaxPull()\fP\&. +.SS "long long * smaxPullLongs (const char * table, const char * key, \fBXMeta\fP * meta, int * n)" +Returns a dynamically allocated array of long long (int64) integers stored in an SMA-X variable\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fImeta\fP (optional) Pointer to metadata to be filled or NULL if not required\&. +.br +\fIn\fP Pointer to which the number of integers is returned (if *n > 0) or else an error code\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Pointer to C int[] array containing *n elements, or NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxPullInts()\fP +.PP +smaxPullShorts() +.PP +\fBsmaxPullLong()\fP +.RE +.PP + +.SS "char * smaxPullRaw (const char * table, const char * key, \fBXMeta\fP * meta, int * status)" +Returns a dynamically allocated buffer with the raw string value stored in SMA-X\&. This call can also be used to get single string values from SMA-X, since for single string the stored raw value is simply the string itself\&. However, to properly retrieve string arrays, you want to use \fBsmaxPullStrings()\fP instead\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fImeta\fP (optional) Pointer to metadata to be filled or NULL if not required\&. +.br +\fIstatus\fP Pointer int which an error status is returned\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Pointer to C array containing the elements of the specified type, or NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxPullStrings()\fP +.RE +.PP + +.PP +References \fBsmaxPull()\fP\&. +.SS "char * smaxPullString (const char * table, const char * key)" +Returns a single string value for a given SMA-X variable, or a NULL if the value could not be retrieved\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Pouinter to the string value stored in SMA-X, or NULL if the value could not be retrieved\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyPullString()\fP +.PP +\fBsmaxPullStrings()\fP +.RE +.PP + +.PP +References \fBsmaxPull()\fP\&. +.SS "char ** smaxPullStrings (const char * table, const char * key, \fBXMeta\fP * meta, int * n)" +Returns an array of pointers to individuals strings inside the retrieved contiguous data buffer\&. Thus, to discard the returned data after use, you must first discard the underlying buffer (as pointed by the first element) before discarding the array of pointers themselves\&. E\&.g\&.: +.PP +\fR char **array = smaxPullStrings('mygroup', 'myfield', &meta); \&.\&.\&. if(array != NULL) { free(array[0]); // discards the underlying contiguous buffer free(array); // discards the array of pointers\&. } \fP +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fImeta\fP (optional) Pointer to metadata to be filled or NULL if not required\&. +.br +\fIn\fP Pointer to which the number of double is returned (if *n > 0) or else an error code\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Pointer to a an array of strings (char *) containing *n elements, or NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxPullString()\fP +.PP +\fBsmaxPullRaw()\fP +.RE +.PP + +.PP +References \fBsmaxGetMetaCount()\fP, \fBsmaxPullRaw()\fP, \fBXMeta::storeBytes\fP, and \fBX_META_INIT\fP\&. +.SS "XStructure * smaxPullStruct (const char * id, \fBXMeta\fP * meta, int * status)" +Returns a dynamically allocated XStrucure for the specified hashtable in SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fIid\fP Aggregated structure ID\&. +.br +\fImeta\fP (optional) Pointer to metadata to be filled or NULL if not required\&. +.br +\fIstatus\fP Pointer int which an error status is returned\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Pointer to an XStructure, or NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyPullStruct()\fP +.PP +xDestroyStruct() +.RE +.PP + +.PP +References \fBsmaxPull()\fP\&. +.SS "int smaxShareBoolean (const char * table, const char * key, boolean value)" +Shares a single boolean value to SMA-X\&. All non-zero values are mapped to '1'\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIvalue\fP A boolean value\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareBooleans()\fP +.RE +.PP + +.PP +References \fBsmaxShareBooleans()\fP\&. +.SS "int smaxShareBooleans (const char * table, const char * key, const boolean * values, int n)" +Shares an array of boolean values to SMA-X\&. All non-zero values are mapped to '1'\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.br +\fIvalues\fP Pointer to boolean[] array\&. +.br +\fIn\fP Number of elements in array to share\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareBoolean()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxShareBytes (const char * table, const char * key, const char * values, int n)" +Shares a binary sequence to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIvalues\fP pointer to the byte buffer\&. +.br +\fIn\fP Number of bytes in buffer to share\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareShorts()\fP +.PP +\fBsmaxShareInts()\fP +.PP +\fBsmaxShareLongs()\fP +.PP +\fBsmaxShareInt()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxShareDouble (const char * table, const char * key, double value)" +Shares a single floating point value to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIvalue\fP floating-point value\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareDoubles()\fP +.PP +\fBsmaxShareFloats()\fP +.RE +.PP + +.PP +References \fBsmaxShareDoubles()\fP\&. +.SS "int smaxShareDoubles (const char * table, const char * key, const double * values, int n)" +Shares an array of doubles to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIvalues\fP Pointer to double[] array\&. +.br +\fIn\fP Number of elements in array to share\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareDouble()\fP +.PP +\fBsmaxShareFloats()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxShareFloats (const char * table, const char * key, const float * values, int n)" +Shares an array of floats to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIvalues\fP Pointer to float[] array\&. +.br +\fIn\fP Number of elements in array to share\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareDouble()\fP +.PP +\fBsmaxShareDoubles()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxShareHex (const char * table, const char * key, long long value)" +Shares a single integer value to SMA-X in a hexadecimal representatin\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIvalue\fP Integer value\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareInt()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxShareInt (const char * table, const char * key, long long value)" +Shares a single integer value to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.br +\fIvalue\fP Integer value\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareHex()\fP +.PP +\fBsmaxShareInts()\fP +.RE +.PP + +.PP +References \fBsmaxShareLongs()\fP\&. +.SS "int smaxShareInts (const char * table, const char * key, const int * values, int n)" +Shares an array of long integers to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIvalues\fP Pointer to int[] array\&. +.br +\fIn\fP Number of elements in array to share\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareLongs()\fP +.PP +\fBsmaxShareShorts()\fP +.PP +\fBsmaxShareBytes()\fP +.PP +\fBsmaxShareInt()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxShareLongs (const char * table, const char * key, const long long * values, int n)" +Shares an array of wide integers to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIvalues\fP Pointer to long long[] array\&. +.br +\fIn\fP Number of elements in array to share\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareInts()\fP +.PP +\fBsmaxShareShorts()\fP +.PP +\fBsmaxShareBytes()\fP +.PP +\fBsmaxShareInt()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxShareShorts (const char * table, const char * key, const short * values, int n)" +Shares an array of shorts to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIvalues\fP Pointer to short[] array\&. +.br +\fIn\fP Number of elements in array to share\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS(0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareInt()\fP +.PP +\fBsmaxShareBytes()\fP +.PP +\fBsmaxShareInts()\fP +.PP +\fBsmaxShareLongs()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxShareString (const char * table, const char * key, const char * sValue)" +Shares a single string value to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIsValue\fP Pointer to string\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareStrings()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxShareStrings (const char * table, const char * key, const char ** sValues, int n)" +Shares an array of strings to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIsValues\fP Pointer to array of string pointers\&. +.br +\fIn\fP Number of elements in array to share\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareString()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxWaitOnSubscribed (const char * table, const char * key, int timeout)" +Waits for a specific pushed entry\&. There must be an active subscription that includes the specified group & variable, or else the call will block indefinitely\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name +.br +\fIkey\fP Variable name to wait on\&. +.br +\fItimeout\fP (s) Timeout value\&. 0 or negative values result in an indefinite wait\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if the variable was updated on some host (or owner)\&. X_NO_INIT if the SMA-X sharing was not initialized via \fBsmaxConnect()\fP\&. X_GROUP_INVALID if the 'group' argument is NULL; X_NAME_INVALID if the 'key' argument is NULL\&. X_REL_PREMATURE if \fBsmaxReleaseWaits()\fP was called\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSubscribe()\fP +.PP +\fBsmaxWaitOnSubscribed()\fP +.PP +\fBsmaxWaitOnSubscribedGroup()\fP +.PP +\fBsmaxWaitOnSubscribedVar()\fP +.PP +\fBsmaxWaitOnAnySubscribed()\fP +.PP +\fBsmaxReleaseWaits()\fP +.RE +.PP + +.SS "int smaxWaitOnSubscribedGroup (const char * matchTable, char ** changedKey, int timeout)" +Waits for changes on a specific group\&. The must be an active subscription including that group, or else the call will block indefinitely\&. +.PP +\fBParameters\fP +.RS 4 +\fImatchTable\fP Hash table name (e\&.g\&. owner ID) to wait on\&. +.br +\fIchangedKey\fP Pointer to the string that holds the name of the variable which unblocked the wait or which is set to NULL\&. The lease of the buffer is for the call only\&. The caller should copy its content if persistent storage is required\&. +.br +\fItimeout\fP (s) Timeout value\&. 0 or negative values result in an indefinite wait\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if a variable was updated on the host\&. X_NO_INIT if the SMA-X sharing was not initialized via \fBsmaxConnect()\fP\&. X_GROUP_INVALID if the table name to match is invalid\&. X_REL_PREMATURE if \fBsmaxReleaseWaits()\fP was called\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSubscribe()\fP +.PP +\fBsmaxWaitOnSubscribedVar()\fP +.PP +\fBsmaxWaitOnSubscribed()\fP +.PP +\fBsmaxWaitOnAnySubscribed()\fP +.PP +\fBsmaxReleaseWaits()\fP +.RE +.PP + +.SS "int smaxWaitOnSubscribedVar (const char * matchKey, char ** changedTable, int timeout)" +Waits for a specific pushed variable from any group/table\&. There must be an active subscription that includes the specified variable in one or more groups/tables, or else the call will block indefinitely\&. +.PP +\fBParameters\fP +.RS 4 +\fImatchKey\fP Variable name to wait on\&. +.br +\fIchangedTable\fP Pointer to the string that holds the name of the table which unblocked the wait or which is set to NULL\&. The lease of the buffer is for the call only\&. The caller should copy its content if persistent storage is required\&. +.br +\fItimeout\fP (s) Timeout value\&. 0 or negative values result in an indefinite wait\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if the variable was updated on some host (or owner)\&. X_NO_INIT if the SMA-X sharing was not initialized via \fBsmaxConnect()\fP\&. X_NAME_INVALID if the 'key' argument is NULL\&. X_REL_PREMATURE if \fBsmaxReleaseWaits()\fP was called\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSubscribe()\fP +.PP +\fBsmaxWaitOnSubscribedGroup()\fP +.PP +\fBsmaxWaitOnSubscribed()\fP +.PP +\fBsmaxWaitOnAnySubscribed()\fP +.PP +\fBsmaxReleaseWaits()\fP +.RE +.PP + +.SH "Author" +.PP +Generated automatically by Doxygen for smax-clib from the source code\&. diff --git a/apidoc/man/man3/smax-lazy.c.3 b/apidoc/man/man3/smax-lazy.c.3 new file mode 100644 index 0000000..5726b24 --- /dev/null +++ b/apidoc/man/man3/smax-lazy.c.3 @@ -0,0 +1,368 @@ +.TH "src/smax-lazy.c" 3 "Version v0.9" "smax-clib" \" -*- nroff -*- +.ad l +.nh +.SH NAME +src/smax-lazy.c \- A set of functions to support the efficient retrieval of lazy variables, that is variables that change infrequently, from the SMA-X database\&. Rather than querying the database on every call, the first lazy pull of a variable initiates monitoring for updates\&. The pull requests will return the current state of the variable at all times, but it generates minimal network traffic only when the underlying value in the database is changed\&. + +.SH SYNOPSIS +.br +.PP +.SS "Functions" + +.in +1c +.ti -1c +.RI "int \fBsmaxGetLazyCached\fP (const char *table, const char *key, XType type, int count, void *value, \fBXMeta\fP *meta)" +.br +.ti -1c +.RI "int \fBsmaxGetLazyUpdateCount\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "int \fBsmaxLazyCache\fP (const char *table, const char *key, XType type)" +.br +.ti -1c +.RI "int \fBsmaxLazyEnd\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "int \fBsmaxLazyFlush\fP ()" +.br +.ti -1c +.RI "int \fBsmaxLazyPull\fP (const char *table, const char *key, XType type, int count, void *value, \fBXMeta\fP *meta)" +.br +.ti -1c +.RI "int \fBsmaxLazyPullChars\fP (const char *table, const char *key, char *buf, int n)" +.br +.ti -1c +.RI "double \fBsmaxLazyPullDouble\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "double \fBsmaxLazyPullDoubleDefault\fP (const char *table, const char *key, double defaultValue)" +.br +.ti -1c +.RI "long long \fBsmaxLazyPullLong\fP (const char *table, const char *key, long long defaultValue)" +.br +.ti -1c +.RI "char * \fBsmaxLazyPullString\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "int \fBsmaxLazyPullStruct\fP (const char *id, XStructure *s)" +.br +.in -1c +.SH "Detailed Description" +.PP +A set of functions to support the efficient retrieval of lazy variables, that is variables that change infrequently, from the SMA-X database\&. Rather than querying the database on every call, the first lazy pull of a variable initiates monitoring for updates\&. The pull requests will return the current state of the variable at all times, but it generates minimal network traffic only when the underlying value in the database is changed\&. + + +.PP +\fBDate\fP +.RS 4 +Jun 24, 2019 +.RE +.PP +\fBAuthor\fP +.RS 4 +Attila Kovacs +.RE +.PP + +.SH "Function Documentation" +.PP +.SS "int smaxGetLazyCached (const char * table, const char * key, XType type, int count, void * value, \fBXMeta\fP * meta)" +Retrieve a variable from the local cache (if available), or else pull from the SMA-X database\&. If local caching was not previously eanbled, it will be enabled with this call, so that subsequent calls will always return data from the locally updated cache with minimal overhead and effectively no latency\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fItype\fP The SMA-X variable type, e\&.g\&. X_FLOAT or X_CHARS(40), of the buffer\&. +.br +\fIcount\fP The number of elements to retrieve +.br +\fIvalue\fP Pointer to the native data buffer in which to restore values +.br +\fImeta\fP Optional metadata pointer, or NULL if metadata is not required\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or X_NO_SERVICE is SMA-X is not accessible, or another error (<0) from \fBsmax\&.h\fP or xchange\&.h\&. +.RE +.PP +\fBSee also\fP +.RS 4 +sa \fBsmaxLazyCache()\fP +.PP +sa smaxLaxyPull() +.RE +.PP + +.SS "int smaxGetLazyUpdateCount (const char * table, const char * key)" +Returns the actual number of times a variable has been updated from SMA-X\&. It may be useful information when deciding if lazy pulling is appropriate (it is if the number of pull requests exceeds the actual number of transfers significantly)\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The number of times a variable has been updated, or -1 if the variable is not being monitored, or if the arguments are invalid\&. +.RE +.PP + +.SS "int smaxLazyCache (const char * table, const char * key, XType type)" +Specify that a specific variable should be cached for minimum overhead lazy access\&. When a variable is lazy cached its local copy is automatically updated in the background so that accessing it is always nearly instantaneous\&. Lazy caching is a good choice for variables that change less frequently than they are polled typically\&. For variables that change frequently (ans used less frequently), lazy caching is not a great choice since it consumes network bandwidth even when the variable is not being accessed\&. +.PP +Once a variable is lazy cached, it can be accessed instantaneously via \fBsmaxGetLazyCached()\fP without any blocking network operations\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fItype\fP The SMA-X variable type, e\&.g\&. X_FLOAT or X_CHARS(40), of the buffer\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) or X_NO_SERVICE\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxGetLazyCached()\fP +.RE +.PP + +.SS "int smaxLazyEnd (const char * table, const char * key)" +Stops processing lazy updates in the background for a given variable\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyFlush()\fP +.PP +\fBsmaxLazyPull()\fP +.RE +.PP + +.SS "int smaxLazyFlush ()" +Discards caches for all lazy variables (i\&.e\&. stops all subscriptions to variable updates, at least until the next \fBsmaxLazyPull()\fP call)\&. Generally speaking, it's a good idea to call this routine when one is done using a set of lazy variables for the time being, but want to avoid the tedium of calling \fBsmaxLazyEnd()\fP individually for each of them\&. Note however, that after flushing the lazy caches, the fist lazy call following for each variable will inevitably result in a real SMA-X pull\&. So use it carefully! +.PP +\fBReturns\fP +.RS 4 +Number of monitor points flushed\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyPull()\fP +.PP +\fBsmaxLazyEnd()\fP +.RE +.PP + +.PP +References \fBsmaxRemoveSubscribers()\fP\&. +.SS "int smaxLazyPull (const char * table, const char * key, XType type, int count, void * value, \fBXMeta\fP * meta)" +Poll an infrequently changing variable without stressing out the network or the SMA-X database\&. The first lazy pull for a variable will fetch its value from SMA-X and subscribe to update notifications\&. Subsequent \fBsmaxLazyPull()\fP calls to the same variable will retrieve its value from a local cache (without contacting SMA-X) as long as it is unchanged\&. +.PP +Note, after you are done using a variable that has been lazy pulled, you should call \fBsmaxLazyEnd()\fP to signal that it no longer requires to be cached and updated in the background, or call \fBsmaxLazyFlush()\fP to flush all lazy caches for all lazy variables (if that is what you want)\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fItype\fP The SMA-X variable type, e\&.g\&. X_FLOAT or X_CHARS(40), of the buffer\&. +.br +\fIcount\fP The number of points to retrieve into the buffer\&. +.br +\fIvalue\fP Pointer to the buffer to which the data is to be retrieved\&. +.br +\fImeta\fP Pointer to metadata or NULL if no metadata is needed\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) on success, or else an error code (<0) of \fBsmaxPull()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyEnd()\fP +.PP +\fBsmaxLazyFlush()\fP +.PP +\fBsmaxPull()\fP +.PP +\fBsmaxQueue()\fP +.RE +.PP + +.SS "int smaxLazyPullChars (const char * table, const char * key, char * buf, int n)" +Lazy pulls a string value into the specified string buffer\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIbuf\fP Buffer to fill with stored data +.br +\fIn\fP Number of bytes to fill in buffer\&. The retrieved data will be truncated as necessary\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or the error code (<0) returned by \fBsmaxLazyPull()\fP\&. +.RE +.PP + +.PP +References \fBsmaxLazyPull()\fP\&. +.SS "double smaxLazyPullDouble (const char * table, const char * key)" +Returns a single double-precision value for a given SMA-X variable, or NAN if the value could not be retrieved\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The floating-point value stored in SMA-X, or NaN if the value could not be retrieved\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyPullDoubleDefault()\fP +.PP +\fBsmaxPullDouble()\fP +.RE +.PP + +.PP +References \fBsmaxLazyPullDoubleDefault()\fP\&. +.SS "double smaxLazyPullDoubleDefault (const char * table, const char * key, double defaultValue)" +Returns a single double-precision value for a given SMA-X variable, or a default value if the value could not be retrieved\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIdefaultValue\fP The value to return in case of an error\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The floating-point value stored in SMA-X, or the specified default if the value could not be retrieved\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyPullDouble()\fP +.PP +\fBsmaxPullDoubleDefault()\fP +.RE +.PP + +.PP +References \fBsmaxLazyPull()\fP\&. +.SS "long long smaxLazyPullLong (const char * table, const char * key, long long defaultValue)" +Returns a single integer value for a given SMA-X variable, or a default value if the value could not be retrieved\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIdefaultValue\fP The value to return in case of an error\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The long integer value stored in SMA-X, or the specified default if the value could not be retrieved\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxPullLong()\fP +.RE +.PP + +.PP +References \fBsmaxLazyPull()\fP\&. +.SS "char * smaxLazyPullString (const char * table, const char * key)" +Returns a single string value for a given SMA-X variable, or a NULL if the value could not be retrieved\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Pointer to the string value stored in SMA-X, or NULL if the value could not be retrieved\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxPullString()\fP +.RE +.PP + +.PP +References \fBsmaxLazyPull()\fP\&. +.SS "int smaxLazyPullStruct (const char * id, XStructure * s)" +Lazy pulls data into a structure, discarding any prior data that the structure might contain\&. +.PP +\fBParameters\fP +.RS 4 +\fIid\fP Aggregate structure ID\&. +.br +\fIs\fP Destination structure to populate with the retrieved fields +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or the error code (<0) returned by \fBsmaxLazyPull()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxPullStruct()\fP +.PP +xCreateStruct() +.RE +.PP + +.PP +References \fBsmaxLazyPull()\fP\&. +.SH "Author" +.PP +Generated automatically by Doxygen for smax-clib from the source code\&. diff --git a/apidoc/man/man3/smax-messages.c.3 b/apidoc/man/man3/smax-messages.c.3 new file mode 100644 index 0000000..72acb32 --- /dev/null +++ b/apidoc/man/man3/smax-messages.c.3 @@ -0,0 +1,297 @@ +.TH "src/smax-messages.c" 3 "Version v0.9" "smax-clib" \" -*- nroff -*- +.ad l +.nh +.SH NAME +src/smax-messages.c \- Simple API for sending and receiving program broadcast messages through SMA-X\&. + +.SH SYNOPSIS +.br +.PP +.SS "Macros" + +.in +1c +.ti -1c +.RI "#define \fBMESSAGES_ID\fP 'messages'" +.br +.RI "Redis PUB_SUB channel head used for program messages\&. " +.ti -1c +.RI "#define \fBMESSAGES_PREFIX\fP \fBMESSAGES_ID\fP X_SEP" +.br +.RI "Prefix for Redis PUB/SUB channel for program messages (e\&.g\&. 'messages:') " +.in -1c +.SS "Functions" + +.in +1c +.ti -1c +.RI "int \fBsmaxAddDefaultMessageProcessor\fP (const char *host, const char *prog, const char *type)" +.br +.ti -1c +.RI "int \fBsmaxAddMessageProcessor\fP (const char *host, const char *prog, const char *type, void(*f)(\fBXMessage\fP *))" +.br +.ti -1c +.RI "int \fBsmaxRemoveMessageProcessor\fP (int id)" +.br +.ti -1c +.RI "int \fBsmaxSendDebug\fP (const char *msg)" +.br +.ti -1c +.RI "int \fBsmaxSendDetail\fP (const char *msg)" +.br +.ti -1c +.RI "int \fBsmaxSendError\fP (const char *msg)" +.br +.ti -1c +.RI "int \fBsmaxSendInfo\fP (const char *msg)" +.br +.ti -1c +.RI "int \fBsmaxSendProgress\fP (double fraction, const char *msg)" +.br +.ti -1c +.RI "int \fBsmaxSendStatus\fP (const char *msg)" +.br +.ti -1c +.RI "int \fBsmaxSendWarning\fP (const char *msg)" +.br +.ti -1c +.RI "void \fBsmaxSetMessageSenderID\fP (const char *id)" +.br +.in -1c +.SH "Detailed Description" +.PP +Simple API for sending and receiving program broadcast messages through SMA-X\&. + + +.PP +\fBAuthor\fP +.RS 4 +Attila Kovacs +.RE +.PP +\fBDate\fP +.RS 4 +Created on 12 December 2020 +.RE +.PP + +.SH "Function Documentation" +.PP +.SS "int smaxAddDefaultMessageProcessor (const char * host, const char * prog, const char * type)" +Report messages to stdout/stderr in default formats\&. +.PP +\fBParameters\fP +.RS 4 +\fIhost\fP Host name where messages originate from, or '*' or NULL if any\&. +.br +\fIprog\fP Program name of message originator, or '*' or NULL if any\&. +.br +\fItype\fP Message type, or '*' or NULL if any\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Serial ID number (> 0) of the message processor, or X_NULL\&. +.RE +.PP + +.PP +References \fBsmaxAddMessageProcessor()\fP\&. +.SS "int smaxAddMessageProcessor (const char * host, const char * prog, const char * type, void(*)(\fBXMessage\fP *) f)" +Adds a message processor function for a specific host (or all hosts), a specific program (or all programs), and a specific message type (or all message types)\&. +.PP +\fBParameters\fP +.RS 4 +\fIhost\fP Host name where messages originate from, or '*' or NULL if any\&. +.br +\fIprog\fP Program name of message originator, or '*' or NULL if any\&. +.br +\fItype\fP Message type, or '*' or NULL if any\&. +.br +\fIf\fP Callback function +.RE +.PP +\fBReturns\fP +.RS 4 +Serial ID number (> 0) of the message processor, or X_NULL if callback function is null, or X_FAILURE if malloc failed\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxRemoveMessageProcessor()\fP +.RE +.PP + +.PP +References \fBMESSAGES_PREFIX\fP, \fBsmaxGetRedis()\fP, and \fBsmaxRemoveMessageProcessor()\fP\&. +.SS "int smaxRemoveMessageProcessor (int id)" +Stops a running message processor\&. +.PP +\fBParameters\fP +.RS 4 +\fIid\fP Message processor ID, as returned by \fBsmaxAddMessageProcessor()\fP +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NULL if no message processor is running by that ID\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxAddMessageProcessor()\fP +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "int smaxSendDebug (const char * msg)" +Broadcast a debugging message via SMA-X (e\&.g\&. program traces)\&. +.PP +\fBParameters\fP +.RS 4 +\fImsg\fP Message text +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an X error\&. +.RE +.PP + +.PP +References \fBSMAX_MSG_DEBUG\fP\&. +.SS "int smaxSendDetail (const char * msg)" +Broadcast non-essential verbose informational detail via SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fImsg\fP Message text +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an X error\&. +.RE +.PP + +.PP +References \fBSMAX_MSG_DETAIL\fP\&. +.SS "int smaxSendError (const char * msg)" +Broadcast an error message via SMA-X\&. Errors should be used for an issues that impair program functionality\&. +.PP +\fBParameters\fP +.RS 4 +\fImsg\fP Message text +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an X error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSendWarning()\fP; +.PP +\fBsmaxSendDebug()\fP; +.RE +.PP + +.PP +References \fBSMAX_MSG_ERROR\fP\&. +.SS "int smaxSendInfo (const char * msg)" +Broadcast an informational message via SMA-X\&. These should be confirmations or essential information reported back to users\&. Non-essential information should be sent with sendDetail() instead\&. +.PP +\fBParameters\fP +.RS 4 +\fImsg\fP Message text +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an X error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +sendDetail() +.PP +sendStatus() +.RE +.PP + +.PP +References \fBSMAX_MSG_INFO\fP\&. +.SS "int smaxSendProgress (double fraction, const char * msg)" +Broadcast a progress update over SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fIfraction\fP (0\&.0:1\&.0) Completion fraction\&. +.br +\fImsg\fP Message text +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an X error\&. +.RE +.PP + +.PP +References \fBSMAX_MSG_DETAIL\fP\&. +.SS "int smaxSendStatus (const char * msg)" +Broadcast a program status update via SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fImsg\fP Message text +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an X error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +sendInfo() +.RE +.PP + +.PP +References \fBSMAX_MSG_STATUS\fP\&. +.SS "int smaxSendWarning (const char * msg)" +Broadcast a warning message via SMA-X\&. Warnings should be used for any potentially problematic issues that nonetheless do not impair program functionality\&. +.PP +\fBParameters\fP +.RS 4 +\fImsg\fP Message text +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an X error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSendError()\fP; +.PP +\fBsmaxSendDebug()\fP; +.RE +.PP + +.PP +References \fBSMAX_MSG_WARNING\fP\&. +.SS "void smaxSetMessageSenderID (const char * id)" +Sets the sender ID for outgoing program messages\&. By default the sender ID is : for the program that calls this function, but it can be modified to use some other SMA-X style hierarchical ID also\&. +.PP +\fBParameters\fP +.RS 4 +\fIid\fP The new sender ID for outgoing program messages, or NULL to reinstate the default : style ID\&. The argument is not referenced and can be deallocated as desired after the call without affecting the newly defined message ID\&. +.RE +.PP + +.SH "Author" +.PP +Generated automatically by Doxygen for smax-clib from the source code\&. diff --git a/apidoc/man/man3/smax-meta.c.3 b/apidoc/man/man3/smax-meta.c.3 new file mode 100644 index 0000000..b2d758c --- /dev/null +++ b/apidoc/man/man3/smax-meta.c.3 @@ -0,0 +1,414 @@ +.TH "src/smax-meta.c" 3 "Version v0.9" "smax-clib" \" -*- nroff -*- +.ad l +.nh +.SH NAME +src/smax-meta.c \- A set of utility functions for manipulating optional static metadata\&. + +.SH SYNOPSIS +.br +.PP +.SS "Functions" + +.in +1c +.ti -1c +.RI "\fBXCoordinateSystem\fP * \fBsmaxCreateCoordinateSystem\fP (int nAxis)" +.br +.ti -1c +.RI "void \fBsmaxDestroyCoordinateSystem\fP (\fBXCoordinateSystem\fP *coords)" +.br +.ti -1c +.RI "\fBXCoordinateAxis\fP * \fBsmaxGetCoordinateAxis\fP (const char *id, int n)" +.br +.ti -1c +.RI "\fBXCoordinateSystem\fP * \fBsmaxGetCoordinateSystem\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "char * \fBsmaxGetDescription\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "char * \fBsmaxGetUnits\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "char * \fBsmaxPullMeta\fP (const char *meta, const char *table, const char *key, int *status)" +.br +.ti -1c +.RI "double \fBsmaxPullTime\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "XType \fBsmaxPullTypeDimension\fP (const char *table, const char *key, int *ndim, int *sizes)" +.br +.ti -1c +.RI "int \fBsmaxPushMeta\fP (const char *meta, const char *table, const char *key, const char *value)" +.br +.ti -1c +.RI "int \fBsmaxSetCoordinateAxis\fP (const char *id, int n, const \fBXCoordinateAxis\fP *axis)" +.br +.ti -1c +.RI "int \fBsmaxSetCoordinateSystem\fP (const char *table, const char *key, const \fBXCoordinateSystem\fP *coords)" +.br +.ti -1c +.RI "int \fBsmaxSetDescription\fP (const char *table, const char *key, const char *description)" +.br +.ti -1c +.RI "int \fBsmaxSetUnits\fP (const char *table, const char *key, const char *unit)" +.br +.in -1c +.SH "Detailed Description" +.PP +A set of utility functions for manipulating optional static metadata\&. + + +.PP +\fBDate\fP +.RS 4 +Mar 24, 2020 +.RE +.PP +\fBAuthor\fP +.RS 4 +Attila Kovacs +.RE +.PP + +.SH "Function Documentation" +.PP +.SS "\fBXCoordinateSystem\fP * smaxCreateCoordinateSystem (int nAxis)" +Creates a coordinate system with the desired dimension, and standard Cartesian coordinates with no labels, or units specified (NULL)\&. +.PP +\fBParameters\fP +.RS 4 +\fInAxis\fP Dimension of the coordiante system, i\&.e\&. number of axes\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Pointer to the new coordinate system structure, or NULL if the coordiate system could not be created as specified\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxDestroyCoordinateSystem()\fP +.RE +.PP + +.PP +References \fBXCoordinateSystem::axis\fP, \fBXCoordinateSystem::nAxis\fP, and \fBXCoordinateAxis::step\fP\&. +.SS "void smaxDestroyCoordinateSystem (\fBXCoordinateSystem\fP * coords)" +Deallocates a coordinate system structure\&. +.PP +\fBParameters\fP +.RS 4 +\fIcoords\fP Pointer to the coordinate system to discard\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxCreateCoordinateSystem()\fP +.RE +.PP + +.PP +References \fBXCoordinateSystem::axis\fP\&. +.SS "\fBXCoordinateAxis\fP * smaxGetCoordinateAxis (const char * id, int n)" +Returns the n'th coordinate axis for a given SMA-X coordinate system table id\&. +.PP +\fBParameters\fP +.RS 4 +\fIid\fP Fully qualified SMA-X coordinate system ID\&. +.br +\fIn\fP The (0-based) index of the coordinate axis +.RE +.PP +\fBReturns\fP +.RS 4 +Pointer to a newly allocated \fBXCoordinateAxis\fP structure or NULL if the axis is undefined, or could not be retrieved from the database\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetCoordinateAxis()\fP +.RE +.PP + +.PP +References \fBXCoordinateAxis::name\fP, \fBXCoordinateAxis::refIndex\fP, \fBXCoordinateAxis::refValue\fP, \fBsmaxGetRedis()\fP, \fBXCoordinateAxis::step\fP, and \fBXCoordinateAxis::unit\fP\&. +.SS "\fBXCoordinateSystem\fP * smaxGetCoordinateSystem (const char * table, const char * key)" +Returns the coordinate system, if any, associated to a given SMA-X variable\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable / field name in table\&. +.RE +.PP +\fBReturns\fP +.RS 4 +A newly allocated coordinate system structure, or NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetCoordinateSystem()\fP +.PP +\fBsmaxGetCoordinateAxis()\fP +.RE +.PP + +.PP +References \fBXCoordinateSystem::axis\fP, \fBMETA_COORDS\fP, \fBXCoordinateSystem::nAxis\fP, and \fBsmaxGetCoordinateAxis()\fP\&. +.SS "char * smaxGetDescription (const char * table, const char * key)" +Returns a concise description of a variable\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable / field name in table\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Variable description or NULL or empty string if the variable has no description assiciated with it\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetDescription()\fP +.RE +.PP + +.PP +References \fBMETA_DESCRIPTION\fP, and \fBsmaxPullMeta()\fP\&. +.SS "char * smaxGetUnits (const char * table, const char * key)" +Returns the physical unit name, if any, for the given variable\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable / field name in table\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Unit name (e\&.g\&. 'W / Hz'), or NULL or empty string if the variable has no designated physical unit\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetUnits()\fP +.RE +.PP + +.PP +References \fBMETA_UNIT\fP, and \fBsmaxPullMeta()\fP\&. +.SS "char * smaxPullMeta (const char * meta, const char * table, const char * key, int * status)" +Retrieves a metadata string value for a given variable from the database +.PP +\fBParameters\fP +.RS 4 +\fImeta\fP Root meta table name, usually something like ''\&. +.br +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable / field name in table\&. +.br +\fIstatus\fP Pointer to int in which to return a X_SUCCESS or an error code\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The string metadata value or NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +setPushMeta() +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "double smaxPullTime (const char * table, const char * key)" +Retrieves the timestamp for a given variable from the database\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name (or NULL if key is an aggregate ID)\&. +.br +\fIkey\fP Variable / field name in table\&. +.RE +.PP +\fBReturns\fP +.RS 4 +(s) UNIX timestamp, as fractional seconds since 1 Jan 1970, or NAN if there was an error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +setPushMeta() +.RE +.PP + +.PP +References \fBSMAX_TIMESTAMPS\fP, and \fBsmaxPullMeta()\fP\&. +.SS "XType smaxPullTypeDimension (const char * table, const char * key, int * ndim, int * sizes)" +Retrieves the timestamp for a given variable from the database\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name (or NULL if key is an aggregate ID)\&. +.br +\fIkey\fP Variable / field name in table\&. +.br +\fIndim\fP Pointer to integer in which to return the dimensionality of the variable, or NULL if not requested\&. +.br +\fIsizes\fP Array to store sizes along each dimension, which should hold X_MAX_DIMS integers, or NULL if dimensions are not requested\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Type of data stored under the specified table/key ID\&. +.RE +.PP +\fBSee also\fP +.RS 4 +setPushMeta() +.RE +.PP + +.PP +References \fBSMAX_DIMS\fP, \fBSMAX_TYPES\fP, \fBsmaxPullMeta()\fP, and \fBsmaxTypeForString()\fP\&. +.SS "int smaxPushMeta (const char * meta, const char * table, const char * key, const char * value)" +Adds/updates metadata associated with an SMA-X variable\&. The data will be pushed via the Redis pipeline channel\&. +.PP +\fBParameters\fP +.RS 4 +\fImeta\fP Root meta table name, usually something like ''\&. +.br +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable / field name in table\&. +.br +\fIvalue\fP Metadata string value\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if the metadata was successfully retrieved X_INCOMPLETE if the meatdata was successfully written but an update notification was not sent or else the return value of redisxSetValue() +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxPullMeta()\fP, redisxSetValue() +.RE +.PP + +.PP +References \fBsmaxGetProgramID()\fP, and \fBsmaxGetRedis()\fP\&. +.SS "int smaxSetCoordinateAxis (const char * id, int n, const \fBXCoordinateAxis\fP * axis)" +Defines the n'th coordinate axis for a given SMA-X coordinate system table id\&. +.PP +\fBParameters\fP +.RS 4 +\fIid\fP Fully qualified SMA-X coordinate system ID\&. +.br +\fIn\fP The (0-based) index of the coordinate axis +.br +\fIaxis\fP Pointer to the structure describing the coordinate axis\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if the coordinate axis was successfully set in the database\&. or else the return value of redisxMultiSet()\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetCoordinateAxis()\fP, redisxMultiSet() +.RE +.PP + +.PP +References \fBXCoordinateAxis::name\fP, \fBXCoordinateAxis::refIndex\fP, \fBXCoordinateAxis::refValue\fP, \fBsmaxGetRedis()\fP, \fBXCoordinateAxis::step\fP, and \fBXCoordinateAxis::unit\fP\&. +.SS "int smaxSetCoordinateSystem (const char * table, const char * key, const \fBXCoordinateSystem\fP * coords)" +Sets the coordinate system metadata for data in the database\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable / field name in table\&. +.br +\fIcoords\fP Pointer to the coordinate system structure associated to this variable\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if the coordinate system was successfully sent to SMA-X or else the first error encountered by xSetCoordinateAxis() +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxGetCoordinateSystem()\fP +.PP +\fBsmaxSetCoordinateAxis()\fP +.RE +.PP + +.PP +References \fBXCoordinateSystem::axis\fP, \fBMETA_COORDS\fP, \fBXCoordinateSystem::nAxis\fP, and \fBsmaxSetCoordinateAxis()\fP\&. +.SS "int smaxSetDescription (const char * table, const char * key, const char * description)" +Sets the static description for a given SMA-X variable\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable / field name in table\&. +.br +\fIdescription\fP Concise but descriptive summary of the meaning of the variable\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) If successful or else the return value of \fBsmaxPushMeta()\fP +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetDescription()\fP, \fBsmaxPushMeta()\fP +.RE +.PP + +.PP +References \fBMETA_DESCRIPTION\fP, and \fBsmaxPushMeta()\fP\&. +.SS "int smaxSetUnits (const char * table, const char * key, const char * unit)" +Sets the physical unit name for a given SMA-X variable\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable / field name in table\&. +.br +\fIunit\fP Standard unit specification, e\&.g\&. 'W / Hz' or 'W Hz**{-1}'\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) If successful or else the return value of \fBsmaxPushMeta()\fP +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxGetUnits()\fP, \fBsmaxPushMeta()\fP +.RE +.PP + +.PP +References \fBMETA_UNIT\fP, and \fBsmaxPushMeta()\fP\&. +.SH "Author" +.PP +Generated automatically by Doxygen for smax-clib from the source code\&. diff --git a/apidoc/man/man3/smax-private.h.3 b/apidoc/man/man3/smax-private.h.3 new file mode 100644 index 0000000..5d9ab85 --- /dev/null +++ b/apidoc/man/man3/smax-private.h.3 @@ -0,0 +1,41 @@ +.TH "include/smax-private.h" 3 "Version v0.9" "smax-clib" \" -*- nroff -*- +.ad l +.nh +.SH NAME +include/smax-private.h \- A set of private SMA-X routines used by the API library but should not be exposed outside\&. + +.SH SYNOPSIS +.br +.PP +.SS "Macros" + +.in +1c +.ti -1c +.RI "#define \fB__XCHANGE_INTERNAL_API__\fP" +.br +.RI "User internal definitions\&. " +.ti -1c +.RI "#define \fBRELEASEID\fP ''" +.br +.RI "Redis PUB/SUB channel prefix for wait release notifications\&. " +.in -1c +.SH "Detailed Description" +.PP +A set of private SMA-X routines used by the API library but should not be exposed outside\&. + + +.PP +\fBDate\fP +.RS 4 +Jun 25, 2019 +.RE +.PP +\fBAuthor\fP +.RS 4 +Attila Kovacs +.RE +.PP + +.SH "Author" +.PP +Generated automatically by Doxygen for smax-clib from the source code\&. diff --git a/apidoc/man/man3/smax-queue.c.3 b/apidoc/man/man3/smax-queue.c.3 new file mode 100644 index 0000000..083179d --- /dev/null +++ b/apidoc/man/man3/smax-queue.c.3 @@ -0,0 +1,211 @@ +.TH "src/smax-queue.c" 3 "Version v0.9" "smax-clib" \" -*- nroff -*- +.ad l +.nh +.SH NAME +src/smax-queue.c \- Functions to support pipelined pull requests from SMA-X\&. Because they don't requite a sequence of round-trips, pipelined pulls can be orders of magnitude faster than staggered regular pull requests\&. + +.SH SYNOPSIS +.br +.PP +.SS "Functions" + +.in +1c +.ti -1c +.RI "\fBXSyncPoint\fP * \fBsmaxCreateSyncPoint\fP ()" +.br +.ti -1c +.RI "void \fBsmaxDestroySyncPoint\fP (\fBXSyncPoint\fP *s)" +.br +.ti -1c +.RI "int \fBsmaxQueue\fP (const char *table, const char *key, XType type, int count, void *value, \fBXMeta\fP *meta)" +.br +.ti -1c +.RI "int \fBsmaxQueueCallback\fP (void(*f)(void *), void *arg)" +.br +.ti -1c +.RI "int \fBsmaxSetMaxPendingPulls\fP (int n)" +.br +.ti -1c +.RI "int \fBsmaxSync\fP (\fBXSyncPoint\fP *sync, int timeoutMillis)" +.br +.ti -1c +.RI "int \fBsmaxWaitQueueComplete\fP (int timeoutMillis)" +.br +.in -1c +.SH "Detailed Description" +.PP +Functions to support pipelined pull requests from SMA-X\&. Because they don't requite a sequence of round-trips, pipelined pulls can be orders of magnitude faster than staggered regular pull requests\&. + + +.PP +\fBDate\fP +.RS 4 +Jun 25, 2019 +.RE +.PP +\fBAuthor\fP +.RS 4 +Attila Kovacs +.RE +.PP + +.SH "Function Documentation" +.PP +.SS "\fBXSyncPoint\fP * smaxCreateSyncPoint ()" +Creates a synchronization point that can be waited upon until all elements queued prior to creation are processed (retrieved from the database\&. +.PP +\fBReturns\fP +.RS 4 +Pointer to a newly created synchronization point that can be waited upon\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSync()\fP +.PP +\fBsmaxQueue()\fP +.PP +\fBsmaxQueueCallback()\fP +.RE +.PP + +.PP +References \fBXSyncPoint::isComplete\fP, \fBXSyncPoint::lock\fP, and \fBXSyncPoint::status\fP\&. +.SS "void smaxDestroySyncPoint (\fBXSyncPoint\fP * s)" +Destroys a synchronization point, releasing the memory space allocated to it\&. +.PP +\fBParameters\fP +.RS 4 +\fIs\fP Pointer to the synchronization point to discard\&. +.RE +.PP + +.PP +References \fBXSyncPoint::isComplete\fP, and \fBXSyncPoint::lock\fP\&. +.SS "int smaxQueue (const char * table, const char * key, XType type, int count, void * value, \fBXMeta\fP * meta)" +Queues a pull requests for pipelined data retrieval\&. Because pipelined pulls are executed on a separate Redis client from the one used for sharing values, e\&.g\&. via \fBsmaxShare()\fP, there is no guarantee as to the order of this pull operation and previously initiated shares from the same thread\&. This would only be an issue if you are trying to use queued read to read back a value you have just shared -- which is not really a good use case anyway, as it generates network traffic for not real reason\&. But, if you must read back a value you have shared, you probably should use a regular \fBsmaxPull()\fP call to ensure ordering\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.br +\fItype\fP SMA-X variable type, e\&.g\&. X_FLOAT or X_CHARS(40), of the buffer\&. +.br +\fIcount\fP Number of points to retrieve into the buffer\&. +.br +\fIvalue\fP Pointer to the buffer to which the data is to be retrieved\&. +.br +\fImeta\fP Pointer to the corresponding metadata structure, or NULL\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful X_NAME_INVALID if the table and key are both NULL X_NULL if the value field is NULL or the return value of xQueue()\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxPull()\fP +.PP +\fBsmaxLazyPull()\fP +.PP +\fBsmaxCreateSyncPoint()\fP +.PP +\fBsmaxQueueCallback()\fP +.RE +.PP + +.PP +References \fBSMAX_PIPE_READ_TIMEOUT_MILLIS\fP\&. +.SS "int smaxQueueCallback (void(*)(void *) f, void * arg)" +Adds a callback function to the queue to be called with the specified argument once all prior requests in the queue have been fullfilled (retrieved from the database)\&. +.PP +As a general rule callbacks added to the pipeline should return very fast, and avoid blocking operations for the most part (using mutexes that may block for very short periods only may be excepted)\&. If the user needs to do more processing, or make blocking calls (e\&.g\&. IO operartions) that may not return for longer periods, the callback should fire off processing in a separate thread, or else simply move the result into another asynchronous processing queue\&. +.PP +\fBParameters\fP +.RS 4 +\fIf\fP The callback function that takes a pointer argument +.br +\fIarg\fP Argument to call the specified function with\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) or else X_NULL if the function parameter is NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxCreateSyncPoint()\fP +.PP +\fBsmaxQueue()\fP +.RE +.PP + +.SS "int smaxSetMaxPendingPulls (int n)" +Configures how many pull requests can be queued in when piped pulls are enabled\&. If the queue reaches the specified limit, no new pull requests can be submitted until responses arrive, draining the queue somewhat\&. +.PP +\fBParameters\fP +.RS 4 +\fIn\fP The maximum number of pull requests that can be queued\&. +.RE +.PP +\fBReturns\fP +.RS 4 +TRUE if the argument was valid, and the queue size was set to it, otherwise FALSE +.RE +.PP + +.SS "int smaxSync (\fBXSyncPoint\fP * sync, int timeoutMillis)" +Waits for the queue to reach the specified sync point, up to an optional timeout limit\&. +.PP +\fBParameters\fP +.RS 4 +\fIsync\fP Pointer to a queued synchronization point\&. +.br +\fItimeoutMillis\fP An optional timeout in milliseconds\&. When set to a positive value The call will be guaranteed to return in the specified interval, whether or not the pipelined reads all succeeded\&. The return value can be used to check for errors or if the call timed out before all data were collected\&. If X_TIMEDOUT is returned, smax_end_bulk_pulls() may be called again to allow more time for the queued read operations to complete\&. 0 or negative timeout values will cause the call to wait indefinitely until reads are complete\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if all reads have completed successfully, or the first read error that was enountered (e\&.g\&. RM_INVALID_KEY), or: X_TIMEDOUT if the call timed out while still awaiting data for the queued read requests\&. X_NULL if the SyncPoint argument is NULL, or its mutex/condition field have not been initialized\&. X_FAILURE if the SyncPoint's mutex has not been initialized\&. +.RE +.PP +or the first pull error encountered in the queue since the current batch began\&. +.PP +\fBSee also\fP +.RS 4 +\fBsmaxCreateSyncPoint()\fP +.PP +\fBsmaxWaitQueueComplete()\fP +.RE +.PP + +.PP +References \fBXSyncPoint::isComplete\fP, \fBXSyncPoint::lock\fP, and \fBXSyncPoint::status\fP\&. +.SS "int smaxWaitQueueComplete (int timeoutMillis)" +Waits until all queued pull requests have been retrieved from the database, or until the specified timeout it reached\&. +.PP +\fBParameters\fP +.RS 4 +\fItimeoutMillis\fP An optional timeout in milliseconds\&. When set to a positive value The call will be guaranteed to return in the specified interval, whether or not the pipelined reads all succeeded\&. The return value can be used to check for errors or if the call timed out before all data were collected\&. If X_TIMEDOUT is returned, smax_end_bulk_pulls() may be called again to allow more time for the queued read operations to complete\&. 0 or negative timeout values will cause the call to wait indefinitely until reads are complete\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if all reads have completed successfully, or the first read error that was enountered (e\&.g\&. RM_INVALID_KEY), or: X_TIMEDOUT if the call timed out while still awaiting data for the queued read requests\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSync()\fP +.RE +.PP + +.PP +References \fBXSyncPoint::isComplete\fP, \fBXSyncPoint::lock\fP, \fBsmaxSync()\fP, and \fBXSyncPoint::status\fP\&. +.SH "Author" +.PP +Generated automatically by Doxygen for smax-clib from the source code\&. diff --git a/apidoc/man/man3/smax-resilient.c.3 b/apidoc/man/man3/smax-resilient.c.3 new file mode 100644 index 0000000..eebd478 --- /dev/null +++ b/apidoc/man/man3/smax-resilient.c.3 @@ -0,0 +1,104 @@ +.TH "src/smax-resilient.c" 3 "Version v0.9" "smax-clib" \" -*- nroff -*- +.ad l +.nh +.SH NAME +src/smax-resilient.c \- This module adds trusty push delivery to SMA-X\&. If the server cannot be reached, push requests are stored and updated locally until the server connection is restored, at which point they are delivered\&. + +.SH SYNOPSIS +.br +.PP +.SS "Functions" + +.in +1c +.ti -1c +.RI "boolean \fBsmaxIsResilient\fP ()" +.br +.ti -1c +.RI "void \fBsmaxSetResilient\fP (boolean value)" +.br +.ti -1c +.RI "void \fBsmaxSetResilientExit\fP (boolean value)" +.br +.in -1c +.SH "Detailed Description" +.PP +This module adds trusty push delivery to SMA-X\&. If the server cannot be reached, push requests are stored and updated locally until the server connection is restored, at which point they are delivered\&. + + +.PP +\fBDate\fP +.RS 4 +Aug 14, 2019 +.RE +.PP +\fBAuthor\fP +.RS 4 +Attila Kovacs +.RE +.PP +.PP +This way, push requests are guaranteed to make it to the database sooner or later as long as the calling program keeps running\&. +.PP +It's mainly useful for daemons that generate infrequent data for the database\&. It's not especially meaningful for simple executables, which are run for limited time without persistence\&. +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetResilient()\fP +.PP +\fBsmaxIsResilient()\fP +.RE +.PP + +.SH "Function Documentation" +.PP +.SS "boolean smaxIsResilient ()" +Checks whether the resiliency feature has been enabled\&. +.PP +\fBReturns\fP +.RS 4 +TRUE if enabled, otherwise FALSE\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetResilient()\fP +.RE +.PP + +.SS "void smaxSetResilient (boolean value)" +Enables the resiliency feature of the library, which keeps track of local changes destined to the database when the database is not reachable, and sending all locally stored updates once the database comes online again\&. However, after sending all pending updates to the remote server, the program may exit (default behavior), unless \fBsmaxSetResilientExit()\fP is set to FALSE (0), so that it can be restarted in a fresh state, setting up subscriptions and scripts again as necessary\&. +.PP +\fBParameters\fP +.RS 4 +\fIvalue\fP TRUE (non-zero) to enable, or FALSE (0) to disable resiliency\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxIsResilient()\fP +.PP +\fBsmaxSetResilientExit()\fP +.RE +.PP + +.PP +References \fBsmaxAddConnectHook()\fP, and \fBsmaxRemoveConnectHook()\fP\&. +.SS "void smaxSetResilientExit (boolean value)" +Sets whether the program should exit in resilient mode, after having pushed all local updates\&. The default is to exit since the reconnecting in resilient mode does not by itself re-establish existing subscriptions\&. However, when subscriptions aren't used, or if they are set up as a connect hook, the user may want the program to simply continue\&. This is possible by passing FALSE (0) as the argument to this call\&. This setting only takes effect when resilient mode is enabled\&. Otherwise, the exit policy is set by the RedisX library\&. +.PP +\fBParameters\fP +.RS 4 +\fIvalue\fP Whether to exit the program after all local updates have been pushed to SMA-X after a recovering from an outage\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetResilient()\fP +.PP +\fBsmaxAddConnectHook()\fP +.RE +.PP + +.SH "Author" +.PP +Generated automatically by Doxygen for smax-clib from the source code\&. diff --git a/apidoc/man/man3/smax-util.c.3 b/apidoc/man/man3/smax-util.c.3 new file mode 100644 index 0000000..0380aef --- /dev/null +++ b/apidoc/man/man3/smax-util.c.3 @@ -0,0 +1,617 @@ +.TH "src/smax-util.c" 3 "Version v0.9" "smax-clib" \" -*- nroff -*- +.ad l +.nh +.SH NAME +src/smax-util.c \- A collection of commonly used functions for the SMA-X library\&. + +.SH SYNOPSIS +.br +.PP +.SS "Functions" + +.in +1c +.ti -1c +.RI "int \fBsmax2xField\fP (XField *f)" +.br +.ti -1c +.RI "int \fBsmax2xStruct\fP (XStructure *s)" +.br +.ti -1c +.RI "XField * \fBsmaxCreateField\fP (const char *name, XType type, int ndim, const int *sizes, const void *value)" +.br +.ti -1c +.RI "\fBXMeta\fP * \fBsmaxCreateMeta\fP ()" +.br +.ti -1c +.RI "int \fBsmaxDeletePattern\fP (const char *pattern)" +.br +.ti -1c +.RI "int \fBsmaxError\fP (const char *func, int errorCode)" +.br +.ti -1c +.RI "const char * \fBsmaxErrorDescription\fP (int code)" +.br +.ti -1c +.RI "int \fBsmaxGetMetaCount\fP (const \fBXMeta\fP *m)" +.br +.ti -1c +.RI "char * \fBsmaxGetScriptSHA1\fP (const char *scriptName, int *status)" +.br +.ti -1c +.RI "int \fBsmaxGetServerTime\fP (struct timespec *t)" +.br +.ti -1c +.RI "double \fBsmaxGetTime\fP (const char *timestamp)" +.br +.ti -1c +.RI "int \fBsmaxParseTime\fP (const char *timestamp, time_t *secs, long *nanosecs)" +.br +.ti -1c +.RI "void \fBsmaxResetMeta\fP (\fBXMeta\fP *m)" +.br +.ti -1c +.RI "int \fBsmaxScriptError\fP (const char *name, int status)" +.br +.ti -1c +.RI "int \fBsmaxScriptErrorAsync\fP (const char *name, int status)" +.br +.ti -1c +.RI "void \fBsmaxSetOrigin\fP (\fBXMeta\fP *m, const char *origin)" +.br +.ti -1c +.RI "int \fBsmaxStringToValues\fP (const char *str, void *value, XType type, int eCount, int *pos)" +.br +.ti -1c +.RI "char * \fBsmaxStringType\fP (XType type)" +.br +.ti -1c +.RI "int \fBsmaxTimestamp\fP (char *buf)" +.br +.ti -1c +.RI "__inline__ int \fBsmaxTimeToString\fP (const struct timespec *time, char *buf)" +.br +.RI "*/ " +.ti -1c +.RI "void \fBsmaxTransmitErrorHandler\fP (Redis *redis, enum redisx_channel channel, const char *op)" +.br +.ti -1c +.RI "XType \fBsmaxTypeForString\fP (const char *type)" +.br +.ti -1c +.RI "int \fBsmaxUnpackStrings\fP (const char *data, int len, int count, char **dst)" +.br +.ti -1c +.RI "char * \fBsmaxValuesToString\fP (const void *value, XType type, int eCount, char *trybuf, int trylength)" +.br +.ti -1c +.RI "int \fBx2smaxField\fP (XField *f)" +.br +.ti -1c +.RI "int \fBx2smaxStruct\fP (XStructure *s)" +.br +.in -1c +.SH "Detailed Description" +.PP +A collection of commonly used functions for the SMA-X library\&. + + +.PP +\fBDate\fP +.RS 4 +Jun 25, 2019 +.RE +.PP +\fBAuthor\fP +.RS 4 +Attila Kovacs +.RE +.PP + +.SH "Function Documentation" +.PP +.SS "int smax2xField (XField * f)" +Converts SMA-X field with serialized string value storage to a standard xchange field with a native value storage\&. +.PP +\fBParameters\fP +.RS 4 +\fIf\fP Pointer to field to convert +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NULL if the input field or the deserialized value is NULL, X_TYPE_INVALID if the field is of a type that cannot be deserialized, or else an error code returned by \fBsmaxStringToValues()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBx2smaxField()\fP +.PP +\fBsmax2xStruct()\fP +.RE +.PP + +.PP +References \fBsmax2xStruct()\fP, and \fBsmaxStringToValues()\fP\&. +.SS "int smax2xStruct (XStructure * s)" +Converts an SMA-X structure with serialized string value storage to a standard xchange structure with a native value storage\&. +.PP +\fBParameters\fP +.RS 4 +\fIs\fP Pointer to structure to convert +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_STRUCT_INVALID if the structure is NULL, or had a NULL substructure, or else an error code returned by \fBsmax2xField()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBx2smaxStruct()\fP +.PP +\fBsmax2xField()\fP +.RE +.PP + +.PP +References \fBsmax2xField()\fP\&. +.SS "XField * smaxCreateField (const char * name, XType type, int ndim, const int * sizes, const void * value)" +Creates a generic field of a given name and type and dimensions using the specified native values\&. It is like \fRxCreateField()\fP except that the field is created in serialized form for SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP Field name +.br +\fItype\fP Storage type, e\&.g\&. X_INT\&. +.br +\fIndim\fP Number of dimensionas (1:20)\&. If ndim < 1, it will be reinterpreted as ndim=1, size[0]=1; +.br +\fIsizes\fP Array of sizes along each dimensions, with at least ndim elements, or NULL with ndim<1\&. +.br +\fIvalue\fP Pointer to the native data location in memory\&. Unless it is of type X_STRUCT, the data stored in the field is a copy (for type X_RAW) or serialized string (otherwise)\&. +.RE +.PP +\fBReturns\fP +.RS 4 +A newly created field with the supplied data, or NULL if there was an error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xSetField() +.RE +.PP + +.PP +References \fBsmaxValuesToString()\fP\&. +.SS "\fBXMeta\fP * smaxCreateMeta ()" +Creates a new SMA-X metadata object with defaults\&. Effectively the same as calling calloc() followed by xResetMeta()\&. +.PP +\fBReturns\fP +.RS 4 +Pointer to a new metadata object initialized to defaults\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBX_META_INIT\fP +.RE +.PP + +.PP +References \fBsmaxResetMeta()\fP\&. +.SS "int smaxDeletePattern (const char * pattern)" +Deletes variables and metadata from SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fIpattern\fP Glob variable name pattern +.RE +.PP +\fBReturns\fP +.RS 4 +The number of variables deleted from the SQL DB +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "int smaxError (const char * func, int errorCode)" +Prints a descriptive error message to stderr, and returns the error code\&. +.PP +\fBParameters\fP +.RS 4 +\fIfunc\fP String that describes the function or location where the error occurred\&. +.br +\fIerrorCode\fP Error code that describes the failure\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Same error code as specified on input\&. +.RE +.PP + +.PP +References \fBsmaxErrorDescription()\fP\&. +.SS "const char * smaxErrorDescription (int code)" +Returns a string description for one of the RM error codes\&. +.PP +\fBParameters\fP +.RS 4 +\fIcode\fP One of the error codes defined in 'xchange\&.h' or in '\fBsmax\&.h\fP' (e\&.g\&. X_NO_PIPELINE) +.RE +.PP + +.SS "int smaxGetMetaCount (const \fBXMeta\fP * m)" +Returns the number of elements stored from a metadata\&. +.PP +\fBParameters\fP +.RS 4 +\fIm\fP pointer to metadata that defines the dimension and shape of elements\&. +.RE +.PP +\fBReturns\fP +.RS 4 +the total number of elements represented by the metadata +.RE +.PP + +.PP +References \fBXMeta::storeDim\fP, and \fBXMeta::storeSizes\fP\&. +.SS "char * smaxGetScriptSHA1 (const char * scriptName, int * status)" +Gets the SHA1 script ID for the currently loaded script with the specified name\&. +.PP +\fBParameters\fP +.RS 4 +\fIscriptName\fP Case-sensitive name of the script, e\&.g\&. 'GetStruct'\&. +.br +\fIstatus\fP Pointer int which to return status, which is X_SUCCESS if the SHA1 id was successfully obtained, or else an appropriate error code\&. +.RE +.PP +\fBReturns\fP +.RS 4 +String buffer with the SHA1 key or NULL if it could not be retrieved\&. (The caller is responsible freeing the buffer after use\&.) +.RE +.PP + +.PP +References \fBSMAX_SCRIPTS\fP, and \fBsmaxGetRedis()\fP\&. +.SS "int smaxGetServerTime (struct timespec * t)" +Returns the current time on the Redis server instance\&. +.PP +\fBParameters\fP +.RS 4 +\fIt\fP Pointer to a timespec structure in which to return the server time\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NO_INIT if not connected to SMA-X, or X_NULL if either argument is NULL, or X_PARSE_ERROR if could not parse the response, or another error returned by redisxCheckRESP()\&. +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "double smaxGetTime (const char * timestamp)" +Returns the a sub-second precision UNIX time value for the given SMA-X timestamp +.PP +\fBParameters\fP +.RS 4 +\fItimestamp\fP The string timestamp returned by SMA-X +.RE +.PP +\fBReturns\fP +.RS 4 +Corresponding UNIX time with sub-second precision, or NAN if the input could not be parsed\&. +.RE +.PP + +.PP +References \fBsmaxParseTime()\fP\&. +.SS "int smaxParseTime (const char * timestamp, time_t * secs, long * nanosecs)" +Parses a timestamp into broken-down UNIX time\&. +.PP +\fBParameters\fP +.RS 4 +\fItimestamp\fP Timestamp string as returned in redis queries; +.br +\fIsecs\fP Pointer to the returned UNIX time (seconds)\&. +.br +\fInanosecs\fP Pointer to the retuned sub-second remainder as nanoseconds, or NULL if nor requested\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS(0) if the timestamp was successfully parsed\&. X_NULL if there was no timestamp (empty or invalid string), or the \fRsecs\fP argument is NULL\&. X_PARSE_ERROR if the seconds could not be parsed\&. 1 if there was an error parsing the nanosec part\&. X_NULL if the secs arhument is NULL +.RE +.PP + +.SS "void smaxResetMeta (\fBXMeta\fP * m)" +Set metadata to their default values\&. After resetting the supplied metadata will have exactly the same content as if it were initialized with the X_META_INIT macro\&. +.PP +\fBParameters\fP +.RS 4 +\fIm\fP Pointer to the metadata that is to be cleared\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBX_META_INIT\fP +.RE +.PP + +.PP +References \fBX_META_INIT\fP\&. +.SS "int smaxScriptError (const char * name, int status)" +SMA-X error handler for when the LUA scripts do not execute\&. It prints a message to stderr, then depending on whether SMA-X is in resilient mode, it will try to reconnect to SMA-X in the background, or else exits the program with X_NO_SERVICE\&. You must not call this function with a locked config mutex (via smaxConfigLock())\&. Instead use the async version of this function after smaxConfigLock()\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP The name of the calling function or name of script (whichever is more informative)\&. +.br +\fIstatus\fP An approprioate error code from xchange\&.h to indicate the type of error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxScriptErrorAsync()\fP +.PP +\fBsmaxSetResilient()\fP +.RE +.PP + +.PP +References \fBsmaxScriptErrorAsync()\fP\&. +.SS "int smaxScriptErrorAsync (const char * name, int status)" +Same as \fBsmaxScriptError()\fP, but can be used after smaxConfigLock()\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP The name of the calling function or name of script (whichever is more informative)\&. +.br +\fIstatus\fP An approprioate error code from xchange\&.h to indicate the type of error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxScriptError()\fP +.PP +\fBsmaxSetResilient()\fP +.RE +.PP + +.PP +References \fBsmaxErrorDescription()\fP, \fBsmaxIsConnected()\fP, and \fBsmaxIsResilient()\fP\&. +.SS "void smaxSetOrigin (\fBXMeta\fP * m, const char * origin)" +Sets the 'origin' field of an SMA-X metadata to the specified value, truncating as necessary to fit into the allotted fixed storage\&. +.PP +\fBParameters\fP +.RS 4 +\fIorigin\fP The origination information, usually as hostname:progname +.br +\fIm\fP Pointer to metadata to set\&. +.RE +.PP + +.PP +References \fBXMeta::origin\fP, and \fBSMAX_ORIGIN_LENGTH\fP\&. +.SS "int smaxStringToValues (const char * str, void * value, XType type, int eCount, int * pos)" +Deserializes a string to binary values\&. +.PP +\fBParameters\fP +.RS 4 +\fIstr\fP Serialized ASCII representation of the data (as stored by Redis)\&. +.br +\fIvalue\fP Pointer to the buffer that will hold the binary values\&. The caller is responsible for ensuring the buffer is sufficiently sized for holding the data for the given variable\&. +.br +\fItype\fP Share type, e\&.g\&. X_INT\&. The types X_RAW, X_STRUCT are not supported by this function\&. +.br +\fIeCount\fP Number of elements to retrieve\&. Ignored for X_STRUCT\&. +.br +\fIpos\fP Parse position, i\&.e\&. the number of characters parsed from the input string\&.\&.\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Number of elements successfully parsed, or a negative error code: +.PP +.nf + X_NULL If the value or str argument is NULL\&. + X_TYPE_INVALID If the type is not supported\&. + X_SIZE_INVALID If size is invalid (e\&.g\&. X_RAW, X_STRUCT) + X_PARSE_ERROR If the tokens could not be parsed in the format expected + +.fi +.PP + +.RE +.PP + +.PP +References \fBsmaxUnpackStrings()\fP\&. +.SS "char * smaxStringType (XType type)" +Returns the string type for a given XType argument as a constant expression\&. For examples X_LONG -> 'int64'\&. +.PP +\fBParameters\fP +.RS 4 +\fItype\fP SMA-X type, e\&.g\&. X_FLOAT +.RE +.PP +\fBReturns\fP +.RS 4 +Corresponding string type, e\&.g\&. 'float'\&. (Default is 'string' -- since typically anything can be represented as strings\&.) +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxTypeForString()\fP +.RE +.PP + +.SS "int smaxTimestamp (char * buf)" +Prints the current time into the supplied buffer with subsecond precision\&. +.PP +\fBParameters\fP +.RS 4 +\fIbuf\fP Pointer to string buffer, must be at least X_TIMESTAMP_LENGTH in size\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Number of characters printed, not including the terminating '\\0', or else an error code (<0) if the \fRbuf\fP argument is NULL\&. +.RE +.PP + +.PP +References \fBsmaxTimeToString()\fP\&. +.SS "__inline__ int smaxTimeToString (const struct timespec * time, char * buf)" + +.PP +*/ Prints the given UNIX time into the supplied buffer with subsecond precision\&. +.PP +\fBParameters\fP +.RS 4 +\fItime\fP Pointer to time value\&. +.br +\fIbuf\fP Pointer to string buffer, must be at least X_TIMESTAMP_LENGTH in size\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Number of characters printed, not including the terminating '\\0', or else an error code (<0) if the \fRbuf\fP argument is NULL\&. +.RE +.PP + +.SS "void smaxTransmitErrorHandler (Redis * redis, enum redisx_channel channel, const char * op)" +The SMA-X error handler for Redis transmit (send or receive) errors\&. It prints a message to stderr, then depending on whether SMA-X is in resilient mode, it will try to reconnect to SMA-X in the background, or else exits the program with X_NO_SERVICE\&. +.PP +\fBParameters\fP +.RS 4 +\fIredis\fP The Redis instance in which the error occurred\&. In case of SMA-X this will always be the Redis instance used by SMA-X\&. +.br +\fIchannel\fP The Redis channel index on which the error occured, such as REDIS_INTERAVTIVE_CHANNEL +.br +\fIop\fP The operation during which the error occurred, e\&.g\&. 'send' or 'read'\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetResilient()\fP +.PP +redisxSetTrasmitErrorHandler() +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP, and \fBsmaxIsResilient()\fP\&. +.SS "XType smaxTypeForString (const char * type)" +Returns the XType for a given case-sensitive type string\&. For example 'float' -> X_FLOAT\&. The value 'raw' will return X_RAW\&. +.PP +\fBParameters\fP +.RS 4 +\fItype\fP String type, e\&.g\&. 'struct'\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Corresponding XType, e\&.g\&. X_STRUCT\&. (The default return value is X_RAW, since all Redis values can be represented as raw strings\&.) +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxStringType()\fP +.RE +.PP + +.SS "int smaxUnpackStrings (const char * data, int len, int count, char ** dst)" +Returns an array of dynamically allocated strings from a packed buffer of consecutive 0-terminated or '\\r'-separated string elements\&. +.PP +\fBParameters\fP +.RS 4 +\fIdata\fP Pointer to the packed string data buffer\&. +.br +\fIlen\fP length of packed string (excl\&. termination)\&. +.br +\fIcount\fP Number of string elements expected\&. If fewer than that are found in the packed data, then the returned array of pointers will be padded with NULL\&. +.br +\fIdst\fP An array of string pointers (of size 'count') which will point to dynamically allocated string (char*) elements\&. The array is assumed to be uninitialized, and elements will be allocated as necessary\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NULL if one of the argument pointers is NULL, or else X_INCOMPLETE if some of the components were too large to unpack (alloc error)\&. +.RE +.PP + +.SS "char * smaxValuesToString (const void * value, XType type, int eCount, char * trybuf, int trylength)" +Serializes binary values into a string representation (for Redis)\&. +.PP +\fBParameters\fP +.RS 4 +\fIvalue\fP Pointer to an array of values, or NULL to produce all zeroes\&. If type is X_STRING value should be a pointer to a char** (array of string pointers), as opposed to X_CHAR(n), which expects a contiguous char* buffer with [n * eCount] length (Note, a char[eCount][n] is equivalent to such a char* buffer)\&. +.br +\fItype\fP Share type, e\&.g\&. X_DOUBLE\&. All type except X_STRUCT are supported\&. +.br +\fIeCount\fP Number of elements (ignored for X_RAW)\&. +.br +\fItrybuf\fP (optional) An optional pointer to a buffer that will be used if sufficient (can be NULL)\&. +.br +\fItrylength\fP (optional) Size of the optional buffer\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The pointer to the string buffer holding the ASCII values\&. It may be the supplied buffer (if sufficient), the input value (if type is X_RAW) or else a dynamically allocated buffer, or NULL if the key is malformed\&. If the returned value is neither the input value nor trybuf, then the caller is responsible for calling free() on the dynamically allocated buffer after use\&. +.RE +.PP + +.SS "int x2smaxField (XField * f)" +Converts a standard xchange field (with a native value storage) to an SMA-X field with serialized string value storage\&. +.PP +\fBParameters\fP +.RS 4 +\fIf\fP Pointer to field to convert +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NULL if the input field or the serialized value is NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmax2xField()\fP +.PP +\fBx2smaxStruct()\fP +.RE +.PP + +.PP +References \fBsmaxValuesToString()\fP, and \fBx2smaxStruct()\fP\&. +.SS "int x2smaxStruct (XStructure * s)" +Converts a standard xchange structure (with a native value storage) to an SMA-X structure with serialized string value storage\&. +.PP +\fBParameters\fP +.RS 4 +\fIs\fP Pointer to structure to convert +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_STRUCT_INVALID if the structure is NULL, or had a NULL substructure\&. X_NULL if there was a field that could not be converted\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmax2xStruct()\fP +.PP +\fBx2smaxField()\fP +.RE +.PP + +.PP +References \fBx2smaxField()\fP\&. +.SH "Author" +.PP +Generated automatically by Doxygen for smax-clib from the source code\&. diff --git a/apidoc/man/man3/smax.c.3 b/apidoc/man/man3/smax.c.3 new file mode 100644 index 0000000..f81d01b --- /dev/null +++ b/apidoc/man/man3/smax.c.3 @@ -0,0 +1,959 @@ +.TH "src/smax.c" 3 "Version v0.9" "smax-clib" \" -*- nroff -*- +.ad l +.nh +.SH NAME +src/smax.c \- SMA-X is a software implementation for SMA shared data, and is the base layer for the software reflective memory (RM) emulation, and DSM replacement\&. It works by communicating TCP/IP messages to a central Redis server\&. + +.SH SYNOPSIS +.br +.PP +.SS "Functions" + +.in +1c +.ti -1c +.RI "int \fBsmaxAddConnectHook\fP (void(*setupCall)(void))" +.br +.ti -1c +.RI "int \fBsmaxAddDisconnectHook\fP (void(*cleanupCall)(void))" +.br +.ti -1c +.RI "int \fBsmaxAddSubscriber\fP (const char *idStem, RedisSubscriberCall f)" +.br +.ti -1c +.RI "int \fBsmaxConnect\fP ()" +.br +.ti -1c +.RI "int \fBsmaxConnectTo\fP (const char *server)" +.br +.ti -1c +.RI "int \fBsmaxDisconnect\fP ()" +.br +.ti -1c +.RI "char * \fBsmaxGetHostName\fP ()" +.br +.ti -1c +.RI "char ** \fBsmaxGetKeys\fP (const char *table, int *n)" +.br +.ti -1c +.RI "char * \fBsmaxGetProgramID\fP ()" +.br +.ti -1c +.RI "Redis * \fBsmaxGetRedis\fP ()" +.br +.ti -1c +.RI "int \fBsmaxIsConnected\fP ()" +.br +.ti -1c +.RI "boolean \fBsmaxIsPipelined\fP ()" +.br +.ti -1c +.RI "boolean \fBsmaxIsVerbose\fP ()" +.br +.ti -1c +.RI "int \fBsmaxKeyCount\fP (const char *table)" +.br +.ti -1c +.RI "int \fBsmaxPull\fP (const char *table, const char *key, XType type, int count, void *value, \fBXMeta\fP *meta)" +.br +.ti -1c +.RI "int \fBsmaxReconnect\fP ()" +.br +.ti -1c +.RI "int \fBsmaxReleaseWaits\fP ()" +.br +.ti -1c +.RI "int \fBsmaxRemoveConnectHook\fP (void(*setupCall)(void))" +.br +.ti -1c +.RI "int \fBsmaxRemoveDisconnectHook\fP (void(*cleanupCall)(void))" +.br +.ti -1c +.RI "int \fBsmaxRemoveSubscribers\fP (RedisSubscriberCall f)" +.br +.ti -1c +.RI "int \fBsmaxSetAuth\fP (const char *username, const char *password)" +.br +.ti -1c +.RI "int \fBsmaxSetDB\fP (int idx)" +.br +.ti -1c +.RI "void \fBsmaxSetHostName\fP (const char *name)" +.br +.ti -1c +.RI "int \fBsmaxSetPipelineConsumer\fP (void(*f)(RESP *))" +.br +.ti -1c +.RI "int \fBsmaxSetPipelined\fP (boolean isEnabled)" +.br +.ti -1c +.RI "int \fBsmaxSetServer\fP (const char *host, int port)" +.br +.ti -1c +.RI "int \fBsmaxSetTcpBuf\fP (int size)" +.br +.ti -1c +.RI "void \fBsmaxSetVerbose\fP (boolean value)" +.br +.ti -1c +.RI "int \fBsmaxShare\fP (const char *table, const char *key, const void *value, XType type, int count)" +.br +.ti -1c +.RI "int \fBsmaxShareArray\fP (const char *table, const char *key, const void *ptr, XType type, int ndim, const int *sizes)" +.br +.ti -1c +.RI "int \fBsmaxShareField\fP (const char *table, const XField *f)" +.br +.ti -1c +.RI "int \fBsmaxShareStruct\fP (const char *id, const XStructure *s)" +.br +.ti -1c +.RI "int \fBsmaxSubscribe\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "int \fBsmaxUnsubscribe\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "int \fBsmaxWaitOnAnySubscribed\fP (char **changedTable, char **changedKey, int timeout)" +.br +.in -1c +.SS "Variables" + +.in +1c +.ti -1c +.RI "char * \fBGET_STRUCT\fP" +.br +.RI "SHA1 key for calling HGetStruct LUA script\&. " +.ti -1c +.RI "char * \fBHGET_WITH_META\fP" +.br +.RI "SHA1 key for calling HGetWithMeta LUA script\&. " +.ti -1c +.RI "char * \fBHMSET_WITH_META\fP" +.br +.RI "SHA1 key for calling HMSetWithMeta LUA script\&. " +.ti -1c +.RI "char * \fBHSET_WITH_META\fP" +.br +.RI "SHA1 key for calling HSetWithMeta LUA script\&. " +.in -1c +.SH "Detailed Description" +.PP +SMA-X is a software implementation for SMA shared data, and is the base layer for the software reflective memory (RM) emulation, and DSM replacement\&. It works by communicating TCP/IP messages to a central Redis server\&. + + +.PP +\fBDate\fP +.RS 4 +Jan 26, 2018 +.RE +.PP +\fBAuthor\fP +.RS 4 +Attila Kovacs +.RE +.PP +.PP +There is also extra functionality, for configuring, performance tweaking, verbosity control, and some convenience methods (e\&.g\&. data serialization/deserialization)\&. +.SH "Function Documentation" +.PP +.SS "int smaxAddConnectHook (void(*)(void) setupCall)" +Add a callback function for when SMA-X is connected\&. It's a wrapper to redisxAddConnectHook()\&. +.PP +\fBParameters\fP +.RS 4 +\fIsetupCall\fP Callback function +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) or an error code (<0) from redisxAddConnectHook()\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxRemoveConnectHook()\fP +.PP +\fBsmaxConnect()\fP +.PP +\fBsmaxConnectTo()\fP +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "int smaxAddDisconnectHook (void(*)(void) cleanupCall)" +Add a callback function for when SMA-X is disconnected\&. It's a wrapper to redisxAddDisconnectHook()\&. +.PP +\fBParameters\fP +.RS 4 +\fIcleanupCall\fP Callback function +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) or an error code (<0) from redisxAddConnectHook()\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxRemoveDisconnectHook()\fP +.PP +\fBsmaxDisconnect()\fP +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "int smaxAddSubscriber (const char * idStem, RedisSubscriberCall f)" +Add a subcriber (callback) function to process incoming PUB/SUB messages for a given SMA-X table (or id)\&. The function should itself check that the channel receiving notification is indeed what it expectes before acting on it, as the callback routine will be invoked for any update inside the specified table, unless the table argument refers to a specific aggregate ID of a single variable\&. This call only registers the callback routine for SMA-X update notifications for variables that begin with the specified stem\&. You will still have to subscrive to any relevant variables with \fBsmaxSubscribe()\fP to enable delivering update notifications for the variables of your choice\&. +.PP +\fBParameters\fP +.RS 4 +\fIidStem\fP Table name or ID stem for which the supplied callback function will be invoked as long as the beginning of the PUB/SUB update channel matches the given stem\&. Alternatively, it can be a fully qualified SMA-X ID (of the form table:key) f a single variable\&. +.br +\fIf\fP The function to call when there is an incoming PUB/SUB update to a channel starting with stem\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS if successful, or else an approriate error code by redisxAddSubscriber() +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSubscribe()\fP +.RE +.PP + +.PP +References \fBSMAX_UPDATES_ROOT\fP, and \fBsmaxGetRedis()\fP\&. +.SS "int smaxConnect ()" +Initializes the SMA-X sharing library in this runtime instance\&. +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS If the library was successfully initialized X_ALREADY_OPEN If SMA-X sharing was already open\&. X_NO_SERVICE If the there was an issue establishing the necessary network connection(s)\&. X_NAME_INVALID If the redis server name lookup failed\&. X_NULL If the Redis IP address is NULL +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetServer()\fP +.PP +\fBsmaxSetAuth()\fP +.PP +\fBsmaxConnectTo()\fP +.PP +\fBsmaxDisconnect()\fP +.PP +\fBsmaxReconnect()\fP +.PP +\fBsmaxIsConnected()\fP +.RE +.PP + +.PP +References \fBSMAX_DEFAULT_HOSTNAME\fP, \fBsmaxAddConnectHook()\fP, \fBsmaxAddDisconnectHook()\fP, \fBsmaxAddSubscriber()\fP, \fBsmaxGetProgramID()\fP, \fBsmaxIsConnected()\fP, \fBsmaxLazyFlush()\fP, \fBsmaxReleaseWaits()\fP, \fBsmaxSetPipelineConsumer()\fP, \fBsmaxSetResilient()\fP, and \fBsmaxTransmitErrorHandler()\fP\&. +.SS "int smaxConnectTo (const char * server)" +Initializes the SMA-X sharing library in this runtime instance with the specified Redis server\&. SMA-X is initialized in resilient mode, so that we'll automatically attempt to reconnect to the Redis server if the connection is severed (once it was established)\&. If that is not the desired behavior, you should call \fRsmaxSetResilient(FALSE)\fP after connecting\&. +.PP +\fBParameters\fP +.RS 4 +\fIserver\fP SMA-X Redis server name or IP address, e\&.g\&. '127\&.0\&.0\&.1'\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS If the library was successfully initialized X_NO_SERVICE If the there was an issue establishing the necessary network connection(s)\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxConnect()\fP +.PP +\fBsmaxDisconnect()\fP +.PP +\fBsmaxReconnect()\fP +.PP +\fBsmaxIsConnected()\fP +.PP +\fBsmaxSetResilient()\fP +.RE +.PP + +.PP +References \fBsmaxConnect()\fP, and \fBsmaxSetServer()\fP\&. +.SS "int smaxDisconnect ()" +Disables the SMA-X sharing capability, closing underlying network connections\&. +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if the sharing was properly ended\&. X_NO_INIT if SMA-X was has not been started prior to this call\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxConnect()\fP +.PP +\fBsmaxConnectTo()\fP +.PP +\fBsmaxReconnect()\fP +.PP +\fBsmaxIsConnected()\fP +.RE +.PP + +.PP +References \fBsmaxIsConnected()\fP\&. +.SS "char * smaxGetHostName ()" +Returns the host name on which this program is running\&. It returns a reference to the same static variable every time\&. As such you should never call free() on the returned value\&. Note, that only the leading part of the host name is returned, so for a host that is registered as 'somenode\&.somedomain' only 'somenode' is returned\&. +.PP +\fBReturns\fP +.RS 4 +The host name string (leading part only)\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetHostName()\fP +.RE +.PP + +.SS "char ** smaxGetKeys (const char * table, int * n)" +Returns a snapshot of the key names stored in a given Redis hash table, ot NULL if there was an error\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Host name or owner ID whose variable to count\&. +.br +\fIn\fP Pointer to which the number of keys (>=0) or an error (<0) is returned\&. An error returned by redisxGetKeys(), or else: +.RE +.PP +X_NO_INIT if the SMA-X sharing was not initialized, e\&.g\&. via \fBsmaxConnect()\fP\&. X_GROUP_INVALID if the table name is invalid\&. X_NULL if the output 'n' pointer is NULL\&. +.PP +\fBReturns\fP +.RS 4 +An array of pointers to the names of Redis keys\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxKeyCount()\fP +.RE +.PP + +.SS "char * smaxGetProgramID ()" +Returns the SMA-X program ID\&. +.PP +\fBReturns\fP +.RS 4 +The SMA-X program ID as :, e\&.g\&. 'hal9000:statusServer'\&. +.RE +.PP + +.PP +References \fBsmaxGetHostName()\fP\&. +.SS "Redis * smaxGetRedis ()" +Returns the Redis connection information for SMA-X +.PP +\fBReturns\fP +.RS 4 +The structure containing the Redis connection data\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxConnect()\fP +.PP +\fBsmaxConnectTo()\fP +.PP +\fBsmaxIsConnected()\fP +.RE +.PP + +.SS "int smaxIsConnected ()" +Checks whether SMA-X sharing is currently open (by a preceding call to \fBsmaxConnect()\fP call\&. +.PP +\fBSee also\fP +.RS 4 +\fBsmaxConnect()\fP +.PP +\fBsmaxConnectTo()\fP +.PP +\fBsmaxDisconnect()\fP +.PP +\fBsmaxReconnect()\fP +.RE +.PP + +.SS "boolean smaxIsPipelined ()" +Check if SMA-X is configured with pipeline mode enabled\&. +.PP +\fBReturns\fP +.RS 4 +TRUE (1) if the pipeline is enabled, or else FALSE (0) +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetPipelined()\fP +.RE +.PP + +.SS "boolean smaxIsVerbose ()" +Checks id verbose reporting is enabled\&. +.PP +\fBReturns\fP +.RS 4 +TRUE if verbose reporting is enabled, otherwise FALSE\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetVerbose()\fP +.RE +.PP + +.SS "int smaxKeyCount (const char * table)" +Retrieve the current number of variables stored on host (or owner ID)\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The number of keys (fields) in the specified table (>= 0), or an error code (<0), such as: X_NO_INIT if the SMA-X sharing was not initialized, e\&.g\&. via smaConnect()\&. X_GROUP_INVALID if the table name is invalid\&. or one of the errors (<0) returned by redisxRequest()\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxGetKeys()\fP +.RE +.PP + +.SS "int smaxPull (const char * table, const char * key, XType type, int count, void * value, \fBXMeta\fP * meta)" +Pull data from the specified hash table\&. This calls data via the interactive client to Redis\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.br +\fItype\fP SMA-X variable type, e\&.g\&. X_FLOAT or X_CHARS(40), of the buffer\&. +.br +\fIcount\fP Number of points to retrieve into the buffer\&. +.br +\fIvalue\fP Pointer to the buffer to which the data is to be retrieved\&. +.br +\fImeta\fP Pointer to metadata or NULL if no metadata is needed\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized\&. X_GROUP_INVALID if the 'table' argument is invalid\&. X_NAME_INVALID if the 'key' argument is invalid\&. X_NULL if an essential argument is NULL or contains NULL\&. X_NO_SERVICE if there was no connection to the Redis server\&. X_FAILURE if there was an underlying failure\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyPull()\fP +.PP +\fBsmaxQueue()\fP +.RE +.PP + +.SS "int smaxReconnect ()" +Reconnects to the SMA-X server\&. It will try connecting repeatedly at regular intervals until the connection is made\&. If resilient mode is enabled, then locally accumulated shares will be sent to the Redis server upon reconnection\&. However, subscriptions are not automatically re-established\&. The caller is responsible for reinstate any necessary subscriptions after the reconnection or via an approproate connection hook\&. +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful X_NO_INIT if SMA-X was never initialized\&. +.RE +.PP +or the error returned by redisxReconnect()\&. +.PP +\fBSee also\fP +.RS 4 +\fBsmaxConnect()\fP +.PP +\fBsmaxConnectTo()\fP +.PP +\fBsmaxDisconnect()\fP +.PP +\fBsmaxIsConnected()\fP +.PP +\fBsmaxSetResilient()\fP +.PP +\fBsmaxAddConnectHook()\fP +.RE +.PP + +.PP +References \fBSMAX_RECONNECT_RETRY_SECONDS\fP\&. +.SS "int smaxReleaseWaits ()" +Unblocks all smax_wait*() calls, which will return X_REL_PREMATURE, as a result\&. +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxWaitOnAnySubscribed()\fP +.RE +.PP + +.PP +References \fBRELEASEID\fP\&. +.SS "int smaxRemoveConnectHook (void(*)(void) setupCall)" +Remove a post-connection callback function\&. It's a wrapper to redisxRemoveConnectHook()\&. +.PP +\fBParameters\fP +.RS 4 +\fIsetupCall\fP Callback function +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) or an error code (<0) from redisxAddConnectHook()\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxAddConnectHook()\fP +.PP +\fBsmaxConnect()\fP +.PP +\fBsmaxConnectTo()\fP +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "int smaxRemoveDisconnectHook (void(*)(void) cleanupCall)" +Remove a post-cdisconnect callback function\&. It's a wrapper to redisxRemiveDisconnectHook()\&. +.PP +\fBParameters\fP +.RS 4 +\fIcleanupCall\fP Callback function +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) or an error code (<0) from redisxAddConnectHook()\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxAddDisconnectHook()\fP +.PP +\fBsmaxDisconnect()\fP +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "int smaxRemoveSubscribers (RedisSubscriberCall f)" +Remove all instances of a subscriber callback function from the current list of functions processing PUB/SUB messages\&. This call only deactivates the callback routine, but does not stop the delivery of update notifications from the Redis server\&. You should therefore also call \fBsmaxUnsubscribe()\fP as appropriate to stop notifications for variables that no longer have associated callbacks\&. +.PP +\fBParameters\fP +.RS 4 +\fIf\fP Function to remove +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or else an error (<0) returned by redisxRemoveSubscriber()\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxUnsubscribe()\fP +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "int smaxSetAuth (const char * username, const char * password)" +Sets the SMA-X database authentication parameters (if any) before connecting to the SMA-X server\&. +.PP +\fBParameters\fP +.RS 4 +\fIusername\fP Redis ACL user name (if any), or NULL for no user-based authentication +.br +\fIpassword\fP Redis database password (if any), or NULL if the database is not password protected +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_ALREADY_OPEN if cannot alter the server configuration because we are already in a connected state\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetServer()\fP +.PP +\fBsmaxConnect()\fP +.RE +.PP + +.PP +References \fBsmaxIsConnected()\fP\&. +.SS "int smaxSetDB (int idx)" +Sets a non-default Redis database index to use for SMA-X before connecting to the SMA-X server\&. +.PP +\fBParameters\fP +.RS 4 +\fIidx\fP The Redis database index to use (if not the default one) +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_ALREADY_OPEN if cannot alter the server configuration because we are already in a connected state\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetServer()\fP +.PP +\fBsmaxConnect()\fP +.RE +.PP + +.PP +References \fBsmaxIsConnected()\fP\&. +.SS "void smaxSetHostName (const char * name)" +Changes the host name to the user-specified value instead of the default (leading component of the value returned by gethostname())\&. Subsequent calls to \fBsmaxGetHostName()\fP will return the newly set value\&. An argument of NULL resets to the default\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP the host name to use, or NULL to revert to the default (leading component of gethostname())\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxGetHostName()\fP +.RE +.PP + +.SS "int smaxSetPipelineConsumer (void(*)(RESP *) f)" +Change the pipeline response consumer function (from it's default or other previous consumer)\&. It is a wrapper for redisxSetPipelineConsumer()\&. +.PP +\fBParameters\fP +.RS 4 +\fIf\fP The function to process ALL pipeline responses from Redis\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or else an error by redisxSetPipelineConsumer() +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetPipelined()\fP +.PP +\fBsmaxIsPipelined()\fP +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "int smaxSetPipelined (boolean isEnabled)" +Enable or disable pipelined write operations (enabled by default)\&. When pipelining, share calls will return as soon as the request is sent to the Redis server, without waiting for a response\&. Instead, responses are consumed asynchronously by a dedicated thread, which will report errors to stderr\&. Pipelined writes can have a significant performance advantage over handshaking at the cost of one extra socket connection to Redis (dedicated to pipelining) and the extra thread consuming responses\&. +.PP +The default state of pipelined writes might vary by platform (e\&.g\&. enabled on Linux, disabled on LynxOS)\&. +.PP +\fBIMPORTANT\fP: calls to \fBsmaxSetPipelined()\fP must precede the call to \fBsmaxConnect()\fP\&. +.PP +\fBParameters\fP +.RS 4 +\fIisEnabled\fP TRUE to enable pipelined writes, FALSE to disable (default is enabled)\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_ALREADY_OPEN if cannot alter the server configuration because we are already in a connected state\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxIsPipelined()\fP +.PP +\fBsmaxSetPipelineConsumer()\fP +.RE +.PP + +.PP +References \fBsmaxIsConnected()\fP\&. +.SS "int smaxSetServer (const char * host, int port)" +Configures the SMA-X server before connecting\&. +.PP +\fBParameters\fP +.RS 4 +\fIhost\fP The SMA-X REdis server host name or IP address\&. +.br +\fIport\fP The Redis port number on the SMA-X server, or <=0 to use the default +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_ALREADY_OPEN if cannot alter the server configuration because we are already in a connected state\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetAuth()\fP +.PP +\fBsmaxSetDB()\fP +.PP +\fBsmaxConnect()\fP +.RE +.PP + +.PP +References \fBsmaxIsConnected()\fP\&. +.SS "int smaxSetTcpBuf (int size)" +Set the size of the TCP/IP buffers (send and receive) for future client connections\&. +.PP +\fBParameters\fP +.RS 4 +\fIsize\fP (bytes) requested buffer size, or <= 0 to use default value +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxConnect\fP; +.RE +.PP + +.PP +References \fBsmaxIsConnected()\fP\&. +.SS "void smaxSetVerbose (boolean value)" +Enable or disable verbose reporting of all SMA-X operations (and possibly some details of them)\&. Reporting is done on the standard output (stdout)\&. It may be useful when debugging programs that use the SMA-X interface\&. Verbose reporting is DISABLED by default\&. +.PP +\fBParameters\fP +.RS 4 +\fIvalue\fP TRUE to enable verbose reporting, or FALSE to disable\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxIsVerbose()\fP +.RE +.PP + +.SS "int smaxShare (const char * table, const char * key, const void * value, XType type, int count)" +Share the data into a Redis hash table over the interactive Redis client\&. It's a fire-and-forget type implementation, which sends the data to Redis, without waiting for confirmation of its arrival\&. The choice improves the efficiency and throughput, and minimizes execution time, of the call, but it also means that a pipelined pull request in quick succession, e\&.g\&. via \fBsmaxQueue()\fP, may return a value on the pipeline client \fIbefore\fP this call is fully executed on the interactive Redis client\&. +.PP +(It is generally unlikely that you will follow this share call with a pipelined pull of the same variable\&. It would not only create superflous network traffic for no good reason, but it also would have unpredictable results\&. So, don't\&.) +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name in which to share entry\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.br +\fIvalue\fP Pointer to the buffer whose data is to be shared\&. +.br +\fItype\fP SMA-X variable type, e\&.g\&. X_FLOAT or X_CHARS(40), of the buffer\&. +.br +\fIcount\fP Number of 1D elements\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized\&. X_GROUP_INVALID if the table name is invalid\&. X_NAME_INVALID if the 'key' argument is invalid\&. X_SIZE_INVALID if count < 1 or count > X_MAX_ELEMENTS X_NULL if the 'value' argument is NULL\&. X_NO_SERVICE if there was no connection to the Redis server\&. X_FAILURE if there was an underlying failure\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareArray()\fP +.PP +\fBsmaxShareField()\fP +.PP +\fBsmaxShareStruct()\fP +.RE +.PP + +.PP +References \fBsmaxShareArray()\fP\&. +.SS "int smaxShareArray (const char * table, const char * key, const void * ptr, XType type, int ndim, const int * sizes)" +Share a multidimensional array, such as an \fRint[][][]\fP, or \fRfloat[][]\fP, in a single atomic transaction\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table in which to write entry\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.br +\fIptr\fP Pointer to the data buffer, such as an \fRint[][][]\fP or \fRfloat[][]\fP\&. +.br +\fItype\fP SMA-X variable type, e\&.g\&. X_FLOAT or X_CHARS(40), of the buffer\&. +.br +\fIndim\fP Dimensionality of the data (0 <= \fRndim\fP <= X_MAX_DIMS)\&. +.br +\fIsizes\fP An array of ints containing the sizes along each dimension\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized\&. X_GROUP_INVALID if the table name is invalid\&. X_NAME_INVALID if the 'key' argument is invalid\&. X_SIZE_INVALID if ndim or sizes are invalid\&. X_NULL if the 'value' argument is NULL\&. X_NO_SERVICE if there was no connection to the Redis server\&. X_FAILURE if there was an underlying failure\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShare()\fP +.RE +.PP + +.PP +References \fBsmaxShareField()\fP, and \fBsmaxValuesToString()\fP\&. +.SS "int smaxShareField (const char * table, const XField * f)" +Share a field object, which may contain any SMA-X data type\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table in which to write entry\&. +.br +\fIf\fP Pointer for XField holding the data to share\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized\&. X_GROUP_INVALID if the table name is invalid\&. X_NAME_INVALID if the 'key' argument is invalid\&. X_SIZE_INVALID if ndim or sizes are invalid\&. X_NULL if the 'value' argument is NULL\&. X_NO_SERVICE if there was no connection to the Redis server\&. X_FAILURE if there was an underlying failure\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShare()\fP +.PP +\fBsmaxShareField()\fP +.PP +\fBsmaxShareStruct()\fP +.PP +xSetField() +.PP +xGetField() +.RE +.PP + +.PP +References \fBsmaxShareStruct()\fP\&. +.SS "int smaxShareStruct (const char * id, const XStructure * s)" +Share a structure, and all its data including recursive sub-structures, in a single atromic transaction\&. +.PP +\fBParameters\fP +.RS 4 +\fIid\fP Structure's ID, i\&.e\&. its own aggregated hash table name\&. +.br +\fIs\fP Pointer to the structure data\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized\&. X_GROUP_INVALID if the table name is invalid\&. X_NAME_INVALID if the 'key' argument is invalid\&. X_NULL if the 'value' argument is NULL\&. X_NO_SERVICE if there was no connection to the Redis server\&. X_FAILURE if there was an underlying failure\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShare()\fP +.PP +\fBsmaxShareField()\fP +.PP +xCreateStruct() +.RE +.PP + +.PP +References \fBsmaxCreateField()\fP\&. +.SS "int smaxSubscribe (const char * table, const char * key)" +Subscribes to a specific key(s) in specific group(s)\&. Both the group and key names may contain Redis subscription patterns, e\&.g\&. '*' or '?', or bound characters in square-brackets, e\&.g\&. '[ab]'\&. The subscription only enables receiving update notifications from Redis for the specified variable or variables\&. After subscribing, you can either wait on the subscribed variables to change, or add callback functions to process subscribed variables changes, via \fBsmaxAddSubscriber()\fP\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Variable group pattern, i\&.e\&. hash-table names\&. (NULL is the same as '*')\&. +.br +\fIkey\fP Variable name pattern\&. (if NULL then subscribes only to the table stem)\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS if successfully subscribed to the Redis distribution channel\&. X_NO_SERVICE if there is no active connection to the Redis server\&. X_NULL if the channel argument is NULL X_NO_INIT if the SMA-X library was not initialized\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxUnsubscribe()\fP +.PP +\fBsmaxWaitOnSubscribed()\fP +.PP +\fBsmaxWaitOnSubscribedGroup()\fP +.PP +\fBsmaxWaitOnSubscribedVar()\fP +.PP +\fBsmaxWaitOnAnySubscribed()\fP +.PP +\fBsmaxAddSubscriber()\fP +.RE +.PP + +.SS "int smaxUnsubscribe (const char * table, const char * key)" +Unsubscribes from a specific key(s) in specific group(s)\&. Both the group and key names may contain Redis subscription patterns, e\&.g\&. '*' or '?', or bound characters in square-brackets, e\&.g\&. '[ab]'\&. Unsubscribing will only stops the delivery of update notifications for the affected varuiables, but does not deactivate the associated callbacks for these added via \fBsmaxAddSubscriber()\fP\&. Therefore you should also call smaxRemovesubscribers() as appropriate to deactivate actions that can no longer get triggered by updates\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Variable group pattern, i\&.e\&. structure or hash-table name(s) (NULL is the same as '*')\&. +.br +\fIkey\fP Variable name pattern\&. (if NULL then unsubscribes only from the table stem)\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS if successfully unsubscribed to the Redis distribution channel\&. X_NO_SERVICE if there is no active connection to the Redis server\&. X_NULL if the channel argument is NULL X_NO_INIT if the SMA-X library was not initialized\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSubscribe()\fP +.PP +\fBsmaxRemoveSubscribers()\fP +.RE +.PP + +.SS "int smaxWaitOnAnySubscribed (char ** changedTable, char ** changedKey, int timeout)" +Waits until any variable was pushed on any host, returning both the host and variable name for the updated value\&. The variable must be already subscribed to with \fBsmaxSubscribe()\fP, or else the wait will not receive update notifications\&. +.PP +\fBParameters\fP +.RS 4 +\fIchangedTable\fP Pointer to the variable that points to the string buffer for the returned table name or NULL\&. The lease of the buffer is for the call only\&. +.br +\fIchangedKey\fP Pointer to the variable that points to the string buffer for the returned variable name or NULL\&. The lease of the buffer is for the call only\&. +.br +\fItimeout\fP (s) Timeout value\&. 0 or negative values result in an indefinite wait\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if a variable was pushed on a host\&. X_NO_INIT if the SMA-X sharing was not initialized via \fBsmaxConnect()\fP\&. X_NO_SERVICE if the connection was broken X_GROUP_INVALID if the buffer for the returned table name is NULL\&. X_NAME_INVALID if the buffer for the returned variable name is NULL\&. X_INTERRUPTED if \fBsmaxReleaseWaits()\fP was called\&. X_INCOMPLETE if the wait timed out\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSubscribe()\fP +.PP +\fBsmaxWaitOnSubscribed()\fP +.PP +\fBsmaxWaitOnSubscribedGroup()\fP +.PP +\fBsmaxReleaseWaits()\fP +.RE +.PP + +.PP +References \fBRELEASEID\fP, and \fBsmaxIsConnected()\fP\&. +.SH "Author" +.PP +Generated automatically by Doxygen for smax-clib from the source code\&. diff --git a/apidoc/man/man3/smax.h.3 b/apidoc/man/man3/smax.h.3 new file mode 100644 index 0000000..4144f76 --- /dev/null +++ b/apidoc/man/man3/smax.h.3 @@ -0,0 +1,3956 @@ +.TH "include/smax.h" 3 "Version v0.9" "smax-clib" \" -*- nroff -*- +.ad l +.nh +.SH NAME +include/smax.h +.SH SYNOPSIS +.br +.PP +.SS "Data Structures" + +.in +1c +.ti -1c +.RI "struct \fBXCoordinateAxis\fP" +.br +.RI "Structure that defines a coordinate axis in an \fBXCoordinateSystem\fP for an SMA-X data array\&. " +.ti -1c +.RI "struct \fBXCoordinateSystem\fP" +.br +.RI "Structure that defines a coordinate system, with one or more \fBXCoordinateAxis\fP\&. " +.ti -1c +.RI "struct \fBXMessage\fP" +.br +.RI "SMA-X program message\&. " +.ti -1c +.RI "struct \fBXMeta\fP" +.br +.RI "SMA-X standard metadata\&. " +.ti -1c +.RI "struct \fBXSyncPoint\fP" +.br +.RI "Synchronization point that can be waited upon when queueing pipelined pulls\&. " +.in -1c +.SS "Macros" + +.in +1c +.ti -1c +.RI "#define \fBMETA_COORDS\fP ''" +.br +.RI "Redis hash table in which data coordinates system descriptions are stored\&. " +.ti -1c +.RI "#define \fBMETA_DESCRIPTION\fP ''" +.br +.RI "Redis hash table in which variable descriptions are stored\&. " +.ti -1c +.RI "#define \fBMETA_UNIT\fP ''" +.br +.RI "Redis hash table in which data physical unit names are stored\&. " +.ti -1c +.RI "#define \fBSMAX_DEFAULT_HOSTNAME\fP 'smax'" +.br +.RI "Host name of Redis server used for SMA-X\&. " +.ti -1c +.RI "#define \fBSMAX_DEFAULT_MAX_QUEUED\fP 1024" +.br +.RI "Maximum number of pull requests allowed to be queued at once\&. " +.ti -1c +.RI "#define \fBSMAX_DEFAULT_PIPELINE_ENABLED\fP TRUE" +.br +.RI "Whether pipelining is enabled by default\&. " +.ti -1c +.RI "#define \fBSMAX_DIMS\fP ''" +.br +.RI "Redis meta table where variable dimensions are stored\&. " +.ti -1c +.RI "#define \fBSMAX_MSG_DEBUG\fP 'debug'" +.br +.RI "Program debug messages (also e\&.g\&. traces)\&. " +.ti -1c +.RI "#define \fBSMAX_MSG_DETAIL\fP 'detail'" +.br +.RI "Program detail (i\&.e\&. verbose messages)\&. " +.ti -1c +.RI "#define \fBSMAX_MSG_ERROR\fP 'error'" +.br +.RI "Program errors\&. " +.ti -1c +.RI "#define \fBSMAX_MSG_INFO\fP 'info'" +.br +.RI "Informational program message\&. " +.ti -1c +.RI "#define \fBSMAX_MSG_PROGRESS\fP 'progress'" +.br +.RI "Program detail (i\&.e\&. verbose messages)\&. " +.ti -1c +.RI "#define \fBSMAX_MSG_STATUS\fP 'status'" +.br +.RI "Program status update\&. " +.ti -1c +.RI "#define \fBSMAX_MSG_WARNING\fP 'warning'" +.br +.RI "Program warnings\&. " +.ti -1c +.RI "#define \fBSMAX_ORIGIN_LENGTH\fP 80" +.br +.RI "(bytes) Maximum length of 'origin' meatdata, including termination\&. " +.ti -1c +.RI "#define \fBSMAX_ORIGINS\fP ''" +.br +.RI "Redis meta table where variable origins are stored\&. " +.ti -1c +.RI "#define \fBSMAX_PIPE_READ_TIMEOUT_MILLIS\fP 3000" +.br +.RI "(ms) Timeout for pipelined (queued) pull requests " +.ti -1c +.RI "#define \fBSMAX_READS\fP ''" +.br +.RI "Redis meta table where the number of times a variable has been read is stored\&. " +.ti -1c +.RI "#define \fBSMAX_RECONNECT_RETRY_SECONDS\fP 3" +.br +.RI "(s) Time between reconnection attempts on lost SMA-X connections\&. " +.ti -1c +.RI "#define \fBSMAX_RESTORE_QUEUE_ON_RECONNECT\fP TRUE" +.br +.RI "Whether read queues are restored if SMA-X is disconnected/reconnected\&. " +.ti -1c +.RI "#define \fBSMAX_SCRIPTS\fP 'scripts'" +.br +.RI "Redis table in which the built-in LUA script hashes are stored\&. " +.ti -1c +.RI "#define \fBSMAX_TIMESTAMPS\fP ''" +.br +.RI "Redis meta table where variable timestamps are stored\&. " +.ti -1c +.RI "#define \fBSMAX_TYPES\fP" +.br +.RI "Redis meta table where variable types are stored\&. " +.ti -1c +.RI "#define \fBSMAX_UPDATES\fP \fBSMAX_UPDATES_ROOT\fP X_SEP" +.br +.RI "PUB/SUB message channel heade for hash table updates\&. " +.ti -1c +.RI "#define \fBSMAX_UPDATES_LENGTH\fP" +.br +.RI "String length of SMA-X update channel prefix\&. " +.ti -1c +.RI "#define \fBSMAX_UPDATES_ROOT\fP 'smax'" +.br +.RI "Notification class for SMA-X updates\&. " +.ti -1c +.RI "#define \fBSMAX_WRITES\fP ''" +.br +.RI "Redis meta table where the number of times a variable has been written is stored\&. " +.ti -1c +.RI "#define \fBX_META_INIT\fP { 0, X_UNKNOWN, \-1, {0}, \-1 }" +.br +.in -1c +.SS "Functions" + +.in +1c +.ti -1c +.RI "int \fBsmax2xField\fP (XField *f)" +.br +.ti -1c +.RI "int \fBsmax2xStruct\fP (XStructure *s)" +.br +.ti -1c +.RI "int \fBsmaxAddConnectHook\fP (void(*setupCall)(void))" +.br +.ti -1c +.RI "int \fBsmaxAddDefaultMessageProcessor\fP (const char *host, const char *prog, const char *type)" +.br +.ti -1c +.RI "int \fBsmaxAddDisconnectHook\fP (void(*cleanupCall)(void))" +.br +.ti -1c +.RI "int \fBsmaxAddMessageProcessor\fP (const char *host, const char *prog, const char *type, void(*f)(\fBXMessage\fP *))" +.br +.ti -1c +.RI "int \fBsmaxAddSubscriber\fP (const char *stem, RedisSubscriberCall f)" +.br +.ti -1c +.RI "int \fBsmaxConnect\fP ()" +.br +.ti -1c +.RI "int \fBsmaxConnectTo\fP (const char *server)" +.br +.ti -1c +.RI "XField * \fBsmaxCreate1DField\fP (const char *name, XType type, int size, const void *value)" +.br +.ti -1c +.RI "XField * \fBsmaxCreateBooleanField\fP (const char *name, boolean value)" +.br +.ti -1c +.RI "\fBXCoordinateSystem\fP * \fBsmaxCreateCoordinateSystem\fP (int nAxis)" +.br +.ti -1c +.RI "XField * \fBsmaxCreateDoubleField\fP (const char *name, double value)" +.br +.ti -1c +.RI "XField * \fBsmaxCreateField\fP (const char *name, XType type, int ndim, const int *sizes, const void *value)" +.br +.ti -1c +.RI "XField * \fBsmaxCreateIntField\fP (const char *name, int value)" +.br +.ti -1c +.RI "XField * \fBsmaxCreateLongField\fP (const char *name, long long value)" +.br +.ti -1c +.RI "\fBXMeta\fP * \fBsmaxCreateMeta\fP ()" +.br +.ti -1c +.RI "XField * \fBsmaxCreateScalarField\fP (const char *name, XType type, const void *value)" +.br +.ti -1c +.RI "XField * \fBsmaxCreateStringField\fP (const char *name, const char *value)" +.br +.ti -1c +.RI "\fBXSyncPoint\fP * \fBsmaxCreateSyncPoint\fP ()" +.br +.ti -1c +.RI "int \fBsmaxDeletePattern\fP (const char *pattern)" +.br +.ti -1c +.RI "void \fBsmaxDestroyCoordinateSystem\fP (\fBXCoordinateSystem\fP *coords)" +.br +.ti -1c +.RI "void \fBsmaxDestroySyncPoint\fP (\fBXSyncPoint\fP *sync)" +.br +.ti -1c +.RI "int \fBsmaxDisconnect\fP ()" +.br +.ti -1c +.RI "int \fBsmaxError\fP (const char *func, int errorCode)" +.br +.ti -1c +.RI "const char * \fBsmaxErrorDescription\fP (int code)" +.br +.ti -1c +.RI "int \fBsmaxGetArrayField\fP (const XStructure *s, const char *name, void *dst, XType type, int count)" +.br +.ti -1c +.RI "boolean \fBsmaxGetBooleanField\fP (const XStructure *s, const char *name, boolean defaultValue)" +.br +.ti -1c +.RI "\fBXCoordinateAxis\fP * \fBsmaxGetCoordinateAxis\fP (const char *id, int n)" +.br +.ti -1c +.RI "\fBXCoordinateSystem\fP * \fBsmaxGetCoordinateSystem\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "char * \fBsmaxGetDescription\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "double \fBsmaxGetDoubleField\fP (const XStructure *s, const char *name, double defaultValue)" +.br +.ti -1c +.RI "char * \fBsmaxGetHostName\fP ()" +.br +.ti -1c +.RI "char ** \fBsmaxGetKeys\fP (const char *table, int *n)" +.br +.ti -1c +.RI "int \fBsmaxGetLazyCached\fP (const char *table, const char *key, XType type, int count, void *value, \fBXMeta\fP *meta)" +.br +.ti -1c +.RI "int \fBsmaxGetLazyUpdateCount\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "long long \fBsmaxGetLongField\fP (const XStructure *s, const char *name, long long defaultValue)" +.br +.ti -1c +.RI "int \fBsmaxGetMetaCount\fP (const \fBXMeta\fP *m)" +.br +.ti -1c +.RI "char * \fBsmaxGetProgramID\fP ()" +.br +.ti -1c +.RI "char * \fBsmaxGetRawField\fP (const XStructure *s, const char *name, char *defaultValue)" +.br +.ti -1c +.RI "Redis * \fBsmaxGetRedis\fP ()" +.br +.ti -1c +.RI "char * \fBsmaxGetScriptSHA1\fP (const char *scriptName, int *status)" +.br +.ti -1c +.RI "int \fBsmaxGetServerTime\fP (struct timespec *t)" +.br +.ti -1c +.RI "double \fBsmaxGetTime\fP (const char *timestamp)" +.br +.ti -1c +.RI "char * \fBsmaxGetUnits\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "int \fBsmaxIsConnected\fP ()" +.br +.ti -1c +.RI "boolean \fBsmaxIsPipelined\fP ()" +.br +.ti -1c +.RI "boolean \fBsmaxIsResilient\fP ()" +.br +.ti -1c +.RI "boolean \fBsmaxIsVerbose\fP ()" +.br +.ti -1c +.RI "int \fBsmaxKeyCount\fP (const char *table)" +.br +.ti -1c +.RI "int \fBsmaxLazyCache\fP (const char *table, const char *key, XType type)" +.br +.ti -1c +.RI "int \fBsmaxLazyEnd\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "int \fBsmaxLazyFlush\fP ()" +.br +.ti -1c +.RI "int \fBsmaxLazyPull\fP (const char *table, const char *key, XType type, int count, void *value, \fBXMeta\fP *meta)" +.br +.ti -1c +.RI "int \fBsmaxLazyPullChars\fP (const char *table, const char *key, char *buf, int n)" +.br +.ti -1c +.RI "double \fBsmaxLazyPullDouble\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "double \fBsmaxLazyPullDoubleDefault\fP (const char *table, const char *key, double defaultValue)" +.br +.ti -1c +.RI "long long \fBsmaxLazyPullLong\fP (const char *table, const char *key, long long defaultValue)" +.br +.ti -1c +.RI "char * \fBsmaxLazyPullString\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "int \fBsmaxLazyPullStruct\fP (const char *id, XStructure *s)" +.br +.ti -1c +.RI "int \fBsmaxParseTime\fP (const char *timestamp, time_t *secs, long *nanosecs)" +.br +.ti -1c +.RI "int \fBsmaxPull\fP (const char *table, const char *key, XType type, int count, void *value, \fBXMeta\fP *meta)" +.br +.ti -1c +.RI "double \fBsmaxPullDouble\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "double \fBsmaxPullDoubleDefault\fP (const char *table, const char *key, double defaultValue)" +.br +.ti -1c +.RI "double * \fBsmaxPullDoubles\fP (const char *table, const char *key, \fBXMeta\fP *meta, int *n)" +.br +.ti -1c +.RI "int \fBsmaxPullInt\fP (const char *table, const char *key, int defaultValue)" +.br +.ti -1c +.RI "int * \fBsmaxPullInts\fP (const char *table, const char *key, \fBXMeta\fP *meta, int *n)" +.br +.ti -1c +.RI "long long \fBsmaxPullLong\fP (const char *table, const char *key, long long defaultValue)" +.br +.ti -1c +.RI "long long * \fBsmaxPullLongs\fP (const char *table, const char *key, \fBXMeta\fP *meta, int *n)" +.br +.ti -1c +.RI "char * \fBsmaxPullMeta\fP (const char *meta, const char *table, const char *key, int *status)" +.br +.ti -1c +.RI "char * \fBsmaxPullRaw\fP (const char *table, const char *key, \fBXMeta\fP *meta, int *status)" +.br +.ti -1c +.RI "char * \fBsmaxPullString\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "char ** \fBsmaxPullStrings\fP (const char *table, const char *key, \fBXMeta\fP *meta, int *n)" +.br +.ti -1c +.RI "XStructure * \fBsmaxPullStruct\fP (const char *name, \fBXMeta\fP *meta, int *status)" +.br +.ti -1c +.RI "double \fBsmaxPullTime\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "XType \fBsmaxPullTypeDimension\fP (const char *table, const char *key, int *ndim, int *sizes)" +.br +.ti -1c +.RI "int \fBsmaxPushMeta\fP (const char *meta, const char *table, const char *key, const char *value)" +.br +.ti -1c +.RI "int \fBsmaxQueue\fP (const char *table, const char *key, XType type, int count, void *value, \fBXMeta\fP *meta)" +.br +.ti -1c +.RI "int \fBsmaxQueueCallback\fP (void(*f)(void *), void *arg)" +.br +.ti -1c +.RI "int \fBsmaxReconnect\fP ()" +.br +.ti -1c +.RI "int \fBsmaxReleaseWaits\fP ()" +.br +.ti -1c +.RI "int \fBsmaxRemoveConnectHook\fP (void(*setupCall)(void))" +.br +.ti -1c +.RI "int \fBsmaxRemoveDisconnectHook\fP (void(*cleanupCall)(void))" +.br +.ti -1c +.RI "int \fBsmaxRemoveMessageProcessor\fP (int id)" +.br +.ti -1c +.RI "int \fBsmaxRemoveSubscribers\fP (RedisSubscriberCall f)" +.br +.ti -1c +.RI "void \fBsmaxResetMeta\fP (\fBXMeta\fP *m)" +.br +.ti -1c +.RI "int \fBsmaxSendDebug\fP (const char *msg)" +.br +.ti -1c +.RI "int \fBsmaxSendDetail\fP (const char *msg)" +.br +.ti -1c +.RI "int \fBsmaxSendError\fP (const char *msg)" +.br +.ti -1c +.RI "int \fBsmaxSendInfo\fP (const char *msg)" +.br +.ti -1c +.RI "int \fBsmaxSendProgress\fP (double fraction, const char *msg)" +.br +.ti -1c +.RI "int \fBsmaxSendStatus\fP (const char *msg)" +.br +.ti -1c +.RI "int \fBsmaxSendWarning\fP (const char *msg)" +.br +.ti -1c +.RI "int \fBsmaxSetAuth\fP (const char *username, const char *password)" +.br +.ti -1c +.RI "int \fBsmaxSetCoordinateAxis\fP (const char *id, int n, const \fBXCoordinateAxis\fP *axis)" +.br +.ti -1c +.RI "int \fBsmaxSetCoordinateSystem\fP (const char *table, const char *key, const \fBXCoordinateSystem\fP *coords)" +.br +.ti -1c +.RI "int \fBsmaxSetDB\fP (int idx)" +.br +.ti -1c +.RI "int \fBsmaxSetDescription\fP (const char *table, const char *key, const char *description)" +.br +.ti -1c +.RI "void \fBsmaxSetHostName\fP (const char *name)" +.br +.ti -1c +.RI "int \fBsmaxSetMaxPendingPulls\fP (int n)" +.br +.ti -1c +.RI "void \fBsmaxSetMessageSenderID\fP (const char *id)" +.br +.ti -1c +.RI "void \fBsmaxSetOrigin\fP (\fBXMeta\fP *m, const char *origin)" +.br +.ti -1c +.RI "int \fBsmaxSetPipelineConsumer\fP (void(*f)(RESP *))" +.br +.ti -1c +.RI "int \fBsmaxSetPipelined\fP (boolean isEnabled)" +.br +.ti -1c +.RI "void \fBsmaxSetResilient\fP (boolean value)" +.br +.ti -1c +.RI "void \fBsmaxSetResilientExit\fP (boolean value)" +.br +.ti -1c +.RI "int \fBsmaxSetServer\fP (const char *host, int port)" +.br +.ti -1c +.RI "int \fBsmaxSetTcpBuf\fP (int size)" +.br +.ti -1c +.RI "int \fBsmaxSetUnits\fP (const char *table, const char *key, const char *unit)" +.br +.ti -1c +.RI "void \fBsmaxSetVerbose\fP (boolean value)" +.br +.ti -1c +.RI "int \fBsmaxShare\fP (const char *table, const char *key, const void *value, XType type, int count)" +.br +.ti -1c +.RI "int \fBsmaxShareArray\fP (const char *table, const char *key, const void *value, XType type, int ndim, const int *sizes)" +.br +.ti -1c +.RI "int \fBsmaxShareBoolean\fP (const char *table, const char *key, boolean value)" +.br +.ti -1c +.RI "int \fBsmaxShareBooleans\fP (const char *table, const char *key, const boolean *values, int n)" +.br +.ti -1c +.RI "int \fBsmaxShareBytes\fP (const char *table, const char *key, const char *values, int n)" +.br +.ti -1c +.RI "int \fBsmaxShareDouble\fP (const char *table, const char *key, double value)" +.br +.ti -1c +.RI "int \fBsmaxShareDoubles\fP (const char *table, const char *key, const double *values, int n)" +.br +.ti -1c +.RI "int \fBsmaxShareField\fP (const char *table, const XField *f)" +.br +.ti -1c +.RI "int \fBsmaxShareFloats\fP (const char *table, const char *key, const float *values, int n)" +.br +.ti -1c +.RI "int \fBsmaxShareHex\fP (const char *table, const char *key, long long value)" +.br +.ti -1c +.RI "int \fBsmaxShareInt\fP (const char *table, const char *key, long long value)" +.br +.ti -1c +.RI "int \fBsmaxShareInts\fP (const char *table, const char *key, const int *values, int n)" +.br +.ti -1c +.RI "int \fBsmaxShareLongs\fP (const char *table, const char *key, const long long *values, int n)" +.br +.ti -1c +.RI "int \fBsmaxShareShorts\fP (const char *table, const char *key, const short *values, int n)" +.br +.ti -1c +.RI "int \fBsmaxShareString\fP (const char *table, const char *key, const char *sValue)" +.br +.ti -1c +.RI "int \fBsmaxShareStrings\fP (const char *table, const char *key, const char **sValues, int n)" +.br +.ti -1c +.RI "int \fBsmaxShareStruct\fP (const char *id, const XStructure *s)" +.br +.ti -1c +.RI "int \fBsmaxStringToValues\fP (const char *str, void *value, XType type, int count, int *parsed)" +.br +.ti -1c +.RI "char * \fBsmaxStringType\fP (XType type)" +.br +.ti -1c +.RI "int \fBsmaxSubscribe\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "int \fBsmaxSync\fP (\fBXSyncPoint\fP *sync, int timeoutMillis)" +.br +.ti -1c +.RI "int \fBsmaxTimestamp\fP (char *buf)" +.br +.ti -1c +.RI "int \fBsmaxTimeToString\fP (const struct timespec *time, char *buf)" +.br +.RI "*/ " +.ti -1c +.RI "XType \fBsmaxTypeForString\fP (const char *type)" +.br +.ti -1c +.RI "int \fBsmaxUnpackStrings\fP (const char *data, int len, int count, char **dst)" +.br +.ti -1c +.RI "int \fBsmaxUnsubscribe\fP (const char *table, const char *key)" +.br +.ti -1c +.RI "char * \fBsmaxValuesToString\fP (const void *value, XType type, int count, char *trybuf, int trylength)" +.br +.ti -1c +.RI "int \fBsmaxWaitOnAnySubscribed\fP (char **changedTable, char **changedKey, int timeout)" +.br +.ti -1c +.RI "int \fBsmaxWaitOnSubscribed\fP (const char *table, const char *key, int timeout)" +.br +.ti -1c +.RI "int \fBsmaxWaitOnSubscribedGroup\fP (const char *matchTable, char **changedKey, int timeout)" +.br +.ti -1c +.RI "int \fBsmaxWaitOnSubscribedVar\fP (const char *matchKey, char **changedTable, int timeout)" +.br +.ti -1c +.RI "int \fBsmaxWaitQueueComplete\fP (int timeoutMillis)" +.br +.ti -1c +.RI "int \fBx2smaxField\fP (XField *f)" +.br +.ti -1c +.RI "int \fBx2smaxStruct\fP (XStructure *s)" +.br +.in -1c +.SH "Detailed Description" +.PP + +.PP +\fBDate\fP +.RS 4 +Jan 26, 2018 +.RE +.PP +\fBAuthor\fP +.RS 4 +Attila Kovacs +.RE +.PP + +.SH "Macro Definition Documentation" +.PP +.SS "#define SMAX_TYPES" + +.PP +Redis meta table where variable types are stored\&. Character arrays a treated somewhat differently, with the element size bundled in the type, to allow variable length strings to be properly parsed into them without overflow\&.\&.\&. +.SS "#define X_META_INIT { 0, X_UNKNOWN, \-1, {0}, \-1 }" +Default initialized for SMA-X medatadata structure\&. You should always initialize local metadata with this\&. +.SH "Function Documentation" +.PP +.SS "int smax2xField (XField * f)" +Converts SMA-X field with serialized string value storage to a standard xchange field with a native value storage\&. +.PP +\fBParameters\fP +.RS 4 +\fIf\fP Pointer to field to convert +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NULL if the input field or the deserialized value is NULL, X_TYPE_INVALID if the field is of a type that cannot be deserialized, or else an error code returned by \fBsmaxStringToValues()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBx2smaxField()\fP +.PP +\fBsmax2xStruct()\fP +.RE +.PP + +.PP +References \fBsmax2xStruct()\fP, and \fBsmaxStringToValues()\fP\&. +.SS "int smax2xStruct (XStructure * s)" +Converts an SMA-X structure with serialized string value storage to a standard xchange structure with a native value storage\&. +.PP +\fBParameters\fP +.RS 4 +\fIs\fP Pointer to structure to convert +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_STRUCT_INVALID if the structure is NULL, or had a NULL substructure, or else an error code returned by \fBsmax2xField()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBx2smaxStruct()\fP +.PP +\fBsmax2xField()\fP +.RE +.PP + +.PP +References \fBsmax2xField()\fP\&. +.SS "int smaxAddConnectHook (void(*)(void) setupCall)" +Add a callback function for when SMA-X is connected\&. It's a wrapper to redisxAddConnectHook()\&. +.PP +\fBParameters\fP +.RS 4 +\fIsetupCall\fP Callback function +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) or an error code (<0) from redisxAddConnectHook()\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxRemoveConnectHook()\fP +.PP +\fBsmaxConnect()\fP +.PP +\fBsmaxConnectTo()\fP +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "int smaxAddDefaultMessageProcessor (const char * host, const char * prog, const char * type)" +Report messages to stdout/stderr in default formats\&. +.PP +\fBParameters\fP +.RS 4 +\fIhost\fP Host name where messages originate from, or '*' or NULL if any\&. +.br +\fIprog\fP Program name of message originator, or '*' or NULL if any\&. +.br +\fItype\fP Message type, or '*' or NULL if any\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Serial ID number (> 0) of the message processor, or X_NULL\&. +.RE +.PP + +.PP +References \fBsmaxAddMessageProcessor()\fP\&. +.SS "int smaxAddDisconnectHook (void(*)(void) cleanupCall)" +Add a callback function for when SMA-X is disconnected\&. It's a wrapper to redisxAddDisconnectHook()\&. +.PP +\fBParameters\fP +.RS 4 +\fIcleanupCall\fP Callback function +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) or an error code (<0) from redisxAddConnectHook()\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxRemoveDisconnectHook()\fP +.PP +\fBsmaxDisconnect()\fP +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "int smaxAddMessageProcessor (const char * host, const char * prog, const char * type, void(*)(\fBXMessage\fP *) f)" +Adds a message processor function for a specific host (or all hosts), a specific program (or all programs), and a specific message type (or all message types)\&. +.PP +\fBParameters\fP +.RS 4 +\fIhost\fP Host name where messages originate from, or '*' or NULL if any\&. +.br +\fIprog\fP Program name of message originator, or '*' or NULL if any\&. +.br +\fItype\fP Message type, or '*' or NULL if any\&. +.br +\fIf\fP Callback function +.RE +.PP +\fBReturns\fP +.RS 4 +Serial ID number (> 0) of the message processor, or X_NULL if callback function is null, or X_FAILURE if malloc failed\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxRemoveMessageProcessor()\fP +.RE +.PP + +.PP +References \fBMESSAGES_PREFIX\fP, \fBsmaxGetRedis()\fP, and \fBsmaxRemoveMessageProcessor()\fP\&. +.SS "int smaxAddSubscriber (const char * idStem, RedisSubscriberCall f)" +Add a subcriber (callback) function to process incoming PUB/SUB messages for a given SMA-X table (or id)\&. The function should itself check that the channel receiving notification is indeed what it expectes before acting on it, as the callback routine will be invoked for any update inside the specified table, unless the table argument refers to a specific aggregate ID of a single variable\&. This call only registers the callback routine for SMA-X update notifications for variables that begin with the specified stem\&. You will still have to subscrive to any relevant variables with \fBsmaxSubscribe()\fP to enable delivering update notifications for the variables of your choice\&. +.PP +\fBParameters\fP +.RS 4 +\fIidStem\fP Table name or ID stem for which the supplied callback function will be invoked as long as the beginning of the PUB/SUB update channel matches the given stem\&. Alternatively, it can be a fully qualified SMA-X ID (of the form table:key) f a single variable\&. +.br +\fIf\fP The function to call when there is an incoming PUB/SUB update to a channel starting with stem\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS if successful, or else an approriate error code by redisxAddSubscriber() +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSubscribe()\fP +.RE +.PP + +.PP +References \fBSMAX_UPDATES_ROOT\fP, and \fBsmaxGetRedis()\fP\&. +.SS "int smaxConnect ()" +Initializes the SMA-X sharing library in this runtime instance\&. +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS If the library was successfully initialized X_ALREADY_OPEN If SMA-X sharing was already open\&. X_NO_SERVICE If the there was an issue establishing the necessary network connection(s)\&. X_NAME_INVALID If the redis server name lookup failed\&. X_NULL If the Redis IP address is NULL +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetServer()\fP +.PP +\fBsmaxSetAuth()\fP +.PP +\fBsmaxConnectTo()\fP +.PP +\fBsmaxDisconnect()\fP +.PP +\fBsmaxReconnect()\fP +.PP +\fBsmaxIsConnected()\fP +.RE +.PP + +.PP +References \fBSMAX_DEFAULT_HOSTNAME\fP, \fBsmaxAddConnectHook()\fP, \fBsmaxAddDisconnectHook()\fP, \fBsmaxAddSubscriber()\fP, \fBsmaxGetProgramID()\fP, \fBsmaxIsConnected()\fP, \fBsmaxLazyFlush()\fP, \fBsmaxReleaseWaits()\fP, \fBsmaxSetPipelineConsumer()\fP, \fBsmaxSetResilient()\fP, and \fBsmaxTransmitErrorHandler()\fP\&. +.SS "int smaxConnectTo (const char * server)" +Initializes the SMA-X sharing library in this runtime instance with the specified Redis server\&. SMA-X is initialized in resilient mode, so that we'll automatically attempt to reconnect to the Redis server if the connection is severed (once it was established)\&. If that is not the desired behavior, you should call \fRsmaxSetResilient(FALSE)\fP after connecting\&. +.PP +\fBParameters\fP +.RS 4 +\fIserver\fP SMA-X Redis server name or IP address, e\&.g\&. '127\&.0\&.0\&.1'\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS If the library was successfully initialized X_NO_SERVICE If the there was an issue establishing the necessary network connection(s)\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxConnect()\fP +.PP +\fBsmaxDisconnect()\fP +.PP +\fBsmaxReconnect()\fP +.PP +\fBsmaxIsConnected()\fP +.PP +\fBsmaxSetResilient()\fP +.RE +.PP + +.PP +References \fBsmaxConnect()\fP, and \fBsmaxSetServer()\fP\&. +.SS "XField * smaxCreate1DField (const char * name, XType type, int size, const void * value)" +Creates a field for 1-D array of a given name and type using specified native values\&. It is like \fRxCreate1DField()\fP except that the field is created in serialized form\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP Field name +.br +\fItype\fP Storage type, e\&.g\&. X_INT\&. +.br +\fIsize\fP Array size\&. +.br +\fIvalue\fP Pointer to the native array in memory\&. +.RE +.PP +\fBReturns\fP +.RS 4 +A newly created field with the supplied data, or NULL if there was an error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xSetField() +.RE +.PP + +.PP +References \fBsmaxCreateField()\fP\&. +.SS "XField * smaxCreateBooleanField (const char * name, boolean value)" +Creates a field holding a single boolean value\&. It is like \fRxCreateBooleanField()\fP except that the field is created in serialized form\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP Field name +.br +\fIvalue\fP Associated value +.RE +.PP +\fBReturns\fP +.RS 4 +A newly created field with the supplied data, or NULL if there was an error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xSetField() +.RE +.PP + +.PP +References \fBsmaxCreateScalarField()\fP\&. +.SS "\fBXCoordinateSystem\fP * smaxCreateCoordinateSystem (int nAxis)" +Creates a coordinate system with the desired dimension, and standard Cartesian coordinates with no labels, or units specified (NULL)\&. +.PP +\fBParameters\fP +.RS 4 +\fInAxis\fP Dimension of the coordiante system, i\&.e\&. number of axes\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Pointer to the new coordinate system structure, or NULL if the coordiate system could not be created as specified\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxDestroyCoordinateSystem()\fP +.RE +.PP + +.PP +References \fBXCoordinateSystem::axis\fP, \fBXCoordinateSystem::nAxis\fP, and \fBXCoordinateAxis::step\fP\&. +.SS "XField * smaxCreateDoubleField (const char * name, double value)" +Creates a field holding a single double-precision value\&. It is like \fRxCreateDoubleField()\fP except that the field is created in serialized form\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP Field name +.br +\fIvalue\fP Associated value +.RE +.PP +\fBReturns\fP +.RS 4 +A newly created field with the supplied data, or NULL if there was an error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xSetField() +.RE +.PP + +.PP +References \fBsmaxCreateScalarField()\fP\&. +.SS "XField * smaxCreateField (const char * name, XType type, int ndim, const int * sizes, const void * value)" +Creates a generic field of a given name and type and dimensions using the specified native values\&. It is like \fRxCreateField()\fP except that the field is created in serialized form for SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP Field name +.br +\fItype\fP Storage type, e\&.g\&. X_INT\&. +.br +\fIndim\fP Number of dimensionas (1:20)\&. If ndim < 1, it will be reinterpreted as ndim=1, size[0]=1; +.br +\fIsizes\fP Array of sizes along each dimensions, with at least ndim elements, or NULL with ndim<1\&. +.br +\fIvalue\fP Pointer to the native data location in memory\&. Unless it is of type X_STRUCT, the data stored in the field is a copy (for type X_RAW) or serialized string (otherwise)\&. +.RE +.PP +\fBReturns\fP +.RS 4 +A newly created field with the supplied data, or NULL if there was an error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xSetField() +.RE +.PP + +.PP +References \fBsmaxValuesToString()\fP\&. +.SS "XField * smaxCreateIntField (const char * name, int value)" +Creates a field holding a single integer value\&. It is like \fRxCreateIntField()\fP except that the field is created in serialized form\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP Field name +.br +\fIvalue\fP Associated value +.RE +.PP +\fBReturns\fP +.RS 4 +A newly created field with the supplied data, or NULL if there was an error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xSetField() +.RE +.PP + +.PP +References \fBsmaxCreateScalarField()\fP\&. +.SS "XField * smaxCreateLongField (const char * name, long long value)" +Creates a field holding a single wide (64-bit) integer value\&. It is like \fRxCreateLongField()\fP except that the field is created in serialized form\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP Field name +.br +\fIvalue\fP Associated value +.RE +.PP +\fBReturns\fP +.RS 4 +A newly created field with the supplied data, or NULL if there was an error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xSetField() +.RE +.PP + +.PP +References \fBsmaxCreateScalarField()\fP\&. +.SS "\fBXMeta\fP * smaxCreateMeta ()" +Creates a new SMA-X metadata object with defaults\&. Effectively the same as calling calloc() followed by xResetMeta()\&. +.PP +\fBReturns\fP +.RS 4 +Pointer to a new metadata object initialized to defaults\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBX_META_INIT\fP +.RE +.PP + +.PP +References \fBsmaxResetMeta()\fP\&. +.SS "XField * smaxCreateScalarField (const char * name, XType type, const void * value)" +Creates a scalar field of a given name and type using the specified native value\&. It is like \fRxCreateScalarField()\fP except that the field is created in serialized form\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP Field name +.br +\fItype\fP Storage type, e\&.g\&. X_INT\&. +.br +\fIvalue\fP Pointer to the native data location in memory\&. +.RE +.PP +\fBReturns\fP +.RS 4 +A newly created scalar field with the supplied data, or NULL if there was an error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xSetField() +.RE +.PP + +.PP +References \fBsmaxCreate1DField()\fP\&. +.SS "XField * smaxCreateStringField (const char * name, const char * value)" +Creates a field holding a single string value\&. It is like \fRxCreateStringField()\fP except that the field is created in serialized form\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP Field name +.br +\fIvalue\fP Associated value +.RE +.PP +\fBReturns\fP +.RS 4 +A newly created field referencing the supplied string, or NULL if there was an error\&. +.RE +.PP + +.PP +References \fBsmaxCreateScalarField()\fP\&. +.SS "\fBXSyncPoint\fP * smaxCreateSyncPoint ()" +Creates a synchronization point that can be waited upon until all elements queued prior to creation are processed (retrieved from the database\&. +.PP +\fBReturns\fP +.RS 4 +Pointer to a newly created synchronization point that can be waited upon\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSync()\fP +.PP +\fBsmaxQueue()\fP +.PP +\fBsmaxQueueCallback()\fP +.RE +.PP + +.PP +References \fBXSyncPoint::isComplete\fP, \fBXSyncPoint::lock\fP, and \fBXSyncPoint::status\fP\&. +.SS "int smaxDeletePattern (const char * pattern)" +Deletes variables and metadata from SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fIpattern\fP Glob variable name pattern +.RE +.PP +\fBReturns\fP +.RS 4 +The number of variables deleted from the SQL DB +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "void smaxDestroyCoordinateSystem (\fBXCoordinateSystem\fP * coords)" +Deallocates a coordinate system structure\&. +.PP +\fBParameters\fP +.RS 4 +\fIcoords\fP Pointer to the coordinate system to discard\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxCreateCoordinateSystem()\fP +.RE +.PP + +.PP +References \fBXCoordinateSystem::axis\fP\&. +.SS "void smaxDestroySyncPoint (\fBXSyncPoint\fP * s)" +Destroys a synchronization point, releasing the memory space allocated to it\&. +.PP +\fBParameters\fP +.RS 4 +\fIs\fP Pointer to the synchronization point to discard\&. +.RE +.PP + +.PP +References \fBXSyncPoint::isComplete\fP, and \fBXSyncPoint::lock\fP\&. +.SS "int smaxDisconnect ()" +Disables the SMA-X sharing capability, closing underlying network connections\&. +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if the sharing was properly ended\&. X_NO_INIT if SMA-X was has not been started prior to this call\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxConnect()\fP +.PP +\fBsmaxConnectTo()\fP +.PP +\fBsmaxReconnect()\fP +.PP +\fBsmaxIsConnected()\fP +.RE +.PP + +.PP +References \fBsmaxIsConnected()\fP\&. +.SS "int smaxError (const char * func, int errorCode)" +Prints a descriptive error message to stderr, and returns the error code\&. +.PP +\fBParameters\fP +.RS 4 +\fIfunc\fP String that describes the function or location where the error occurred\&. +.br +\fIerrorCode\fP Error code that describes the failure\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Same error code as specified on input\&. +.RE +.PP + +.PP +References \fBsmaxErrorDescription()\fP\&. +.SS "const char * smaxErrorDescription (int code)" +Returns a string description for one of the RM error codes\&. +.PP +\fBParameters\fP +.RS 4 +\fIcode\fP One of the error codes defined in 'xchange\&.h' or in '\fBsmax\&.h\fP' (e\&.g\&. X_NO_PIPELINE) +.RE +.PP + +.SS "int smaxGetArrayField (const XStructure * s, const char * name, void * dst, XType type, int count)" +Gets the data of an SMA-X structure field as an array of values of the specified type and element count\&. The field's data will be truncated or padded with zeroes to provide the requested element count always\&. +.PP +\fBParameters\fP +.RS 4 +\fIs\fP Pointer to SMA-X structure +.br +\fIname\fP Field name +.br +\fIdst\fP Array to return values in\&. +.br +\fItype\fP Type of data\&. +.br +\fIcount\fP Number of elements in return array\&. The field data will be truncated or padded as necessary\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_STRUCT_INVALID if the input structure is NULL, X_NULL if dst is NULL, X_SIZE_INVALID if n is 0 or negative, X_NAME_INVALID if the structure does not have a field by the specified name, or else an error returned by smaxStringtoValues()\&. +.RE +.PP + +.PP +References \fBsmaxStringToValues()\fP\&. +.SS "boolean smaxGetBooleanField (const XStructure * s, const char * name, boolean defaultValue)" +Returns the first value in a structure's field as an integer, or the specified default value if there is no such field in the structure, or the content cannot be parse into an integer\&. +.PP +\fBParameters\fP +.RS 4 +\fIs\fP Pointer to the XStructure\&. +.br +\fIname\fP Field name +.br +\fIdefaultValue\fP Value to return if no corresponding integer field value\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The (first) field value as a long long, or the default value if there is no such field\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xGetField() +.RE +.PP + +.SS "\fBXCoordinateAxis\fP * smaxGetCoordinateAxis (const char * id, int n)" +Returns the n'th coordinate axis for a given SMA-X coordinate system table id\&. +.PP +\fBParameters\fP +.RS 4 +\fIid\fP Fully qualified SMA-X coordinate system ID\&. +.br +\fIn\fP The (0-based) index of the coordinate axis +.RE +.PP +\fBReturns\fP +.RS 4 +Pointer to a newly allocated \fBXCoordinateAxis\fP structure or NULL if the axis is undefined, or could not be retrieved from the database\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetCoordinateAxis()\fP +.RE +.PP + +.PP +References \fBXCoordinateAxis::name\fP, \fBXCoordinateAxis::refIndex\fP, \fBXCoordinateAxis::refValue\fP, \fBsmaxGetRedis()\fP, \fBXCoordinateAxis::step\fP, and \fBXCoordinateAxis::unit\fP\&. +.SS "\fBXCoordinateSystem\fP * smaxGetCoordinateSystem (const char * table, const char * key)" +Returns the coordinate system, if any, associated to a given SMA-X variable\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable / field name in table\&. +.RE +.PP +\fBReturns\fP +.RS 4 +A newly allocated coordinate system structure, or NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetCoordinateSystem()\fP +.PP +\fBsmaxGetCoordinateAxis()\fP +.RE +.PP + +.PP +References \fBXCoordinateSystem::axis\fP, \fBMETA_COORDS\fP, \fBXCoordinateSystem::nAxis\fP, and \fBsmaxGetCoordinateAxis()\fP\&. +.SS "char * smaxGetDescription (const char * table, const char * key)" +Returns a concise description of a variable\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable / field name in table\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Variable description or NULL or empty string if the variable has no description assiciated with it\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetDescription()\fP +.RE +.PP + +.PP +References \fBMETA_DESCRIPTION\fP, and \fBsmaxPullMeta()\fP\&. +.SS "double smaxGetDoubleField (const XStructure * s, const char * name, double defaultValue)" +Returns the first value in a structure's field as a double precision float, or the specified default value if there is no such field in the structure, or the content cannot be parse into an double\&. +.PP +\fBParameters\fP +.RS 4 +\fIs\fP Pointer to the XStructure\&. +.br +\fIname\fP Field name +.br +\fIdefaultValue\fP Value to return if no corresponding integer field value\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The (first) field value as a double, or the specified default if there is no such field\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xGetField() +.RE +.PP + +.SS "char * smaxGetHostName ()" +Returns the host name on which this program is running\&. It returns a reference to the same static variable every time\&. As such you should never call free() on the returned value\&. Note, that only the leading part of the host name is returned, so for a host that is registered as 'somenode\&.somedomain' only 'somenode' is returned\&. +.PP +\fBReturns\fP +.RS 4 +The host name string (leading part only)\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetHostName()\fP +.RE +.PP + +.SS "char ** smaxGetKeys (const char * table, int * n)" +Returns a snapshot of the key names stored in a given Redis hash table, ot NULL if there was an error\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Host name or owner ID whose variable to count\&. +.br +\fIn\fP Pointer to which the number of keys (>=0) or an error (<0) is returned\&. An error returned by redisxGetKeys(), or else: +.RE +.PP +X_NO_INIT if the SMA-X sharing was not initialized, e\&.g\&. via \fBsmaxConnect()\fP\&. X_GROUP_INVALID if the table name is invalid\&. X_NULL if the output 'n' pointer is NULL\&. +.PP +\fBReturns\fP +.RS 4 +An array of pointers to the names of Redis keys\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxKeyCount()\fP +.RE +.PP + +.SS "int smaxGetLazyCached (const char * table, const char * key, XType type, int count, void * value, \fBXMeta\fP * meta)" +Retrieve a variable from the local cache (if available), or else pull from the SMA-X database\&. If local caching was not previously eanbled, it will be enabled with this call, so that subsequent calls will always return data from the locally updated cache with minimal overhead and effectively no latency\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fItype\fP The SMA-X variable type, e\&.g\&. X_FLOAT or X_CHARS(40), of the buffer\&. +.br +\fIcount\fP The number of elements to retrieve +.br +\fIvalue\fP Pointer to the native data buffer in which to restore values +.br +\fImeta\fP Optional metadata pointer, or NULL if metadata is not required\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or X_NO_SERVICE is SMA-X is not accessible, or another error (<0) from \fBsmax\&.h\fP or xchange\&.h\&. +.RE +.PP +\fBSee also\fP +.RS 4 +sa \fBsmaxLazyCache()\fP +.PP +sa smaxLaxyPull() +.RE +.PP + +.SS "int smaxGetLazyUpdateCount (const char * table, const char * key)" +Returns the actual number of times a variable has been updated from SMA-X\&. It may be useful information when deciding if lazy pulling is appropriate (it is if the number of pull requests exceeds the actual number of transfers significantly)\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The number of times a variable has been updated, or -1 if the variable is not being monitored, or if the arguments are invalid\&. +.RE +.PP + +.SS "long long smaxGetLongField (const XStructure * s, const char * name, long long defaultValue)" +Returns the first value in a structure's field as an integer, or the specified default value if there is no such field in the structure, or the content cannot be parse into an integer\&. +.PP +\fBParameters\fP +.RS 4 +\fIs\fP Pointer to the XStructure\&. +.br +\fIname\fP Field name +.br +\fIdefaultValue\fP Value to return if no corresponding integer field value\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The (first) field value as a long long, or the default value if there is no such field\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xGetField() +.RE +.PP + +.SS "int smaxGetMetaCount (const \fBXMeta\fP * m)" +Returns the number of elements stored from a metadata\&. +.PP +\fBParameters\fP +.RS 4 +\fIm\fP pointer to metadata that defines the dimension and shape of elements\&. +.RE +.PP +\fBReturns\fP +.RS 4 +the total number of elements represented by the metadata +.RE +.PP + +.PP +References \fBXMeta::storeDim\fP, and \fBXMeta::storeSizes\fP\&. +.SS "char * smaxGetProgramID ()" +Returns the SMA-X program ID\&. +.PP +\fBReturns\fP +.RS 4 +The SMA-X program ID as :, e\&.g\&. 'hal9000:statusServer'\&. +.RE +.PP + +.PP +References \fBsmaxGetHostName()\fP\&. +.SS "char * smaxGetRawField (const XStructure * s, const char * name, char * defaultValue)" +Returns the string value in a structure's field, or the specified default value if there is no such field in the structure\&. +.PP +\fBParameters\fP +.RS 4 +\fIs\fP Pointer to the XStructure\&. +.br +\fIname\fP Field name +.br +\fIdefaultValue\fP Value to return if no corresponding integer field value\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The field's string (raw) value, or the specified default if there is no such field\&. +.RE +.PP +\fBSee also\fP +.RS 4 +xGetField() +.RE +.PP + +.SS "Redis * smaxGetRedis ()" +Returns the Redis connection information for SMA-X +.PP +\fBReturns\fP +.RS 4 +The structure containing the Redis connection data\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxConnect()\fP +.PP +\fBsmaxConnectTo()\fP +.PP +\fBsmaxIsConnected()\fP +.RE +.PP + +.SS "char * smaxGetScriptSHA1 (const char * scriptName, int * status)" +Gets the SHA1 script ID for the currently loaded script with the specified name\&. +.PP +\fBParameters\fP +.RS 4 +\fIscriptName\fP Case-sensitive name of the script, e\&.g\&. 'GetStruct'\&. +.br +\fIstatus\fP Pointer int which to return status, which is X_SUCCESS if the SHA1 id was successfully obtained, or else an appropriate error code\&. +.RE +.PP +\fBReturns\fP +.RS 4 +String buffer with the SHA1 key or NULL if it could not be retrieved\&. (The caller is responsible freeing the buffer after use\&.) +.RE +.PP + +.PP +References \fBSMAX_SCRIPTS\fP, and \fBsmaxGetRedis()\fP\&. +.SS "int smaxGetServerTime (struct timespec * t)" +Returns the current time on the Redis server instance\&. +.PP +\fBParameters\fP +.RS 4 +\fIt\fP Pointer to a timespec structure in which to return the server time\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NO_INIT if not connected to SMA-X, or X_NULL if either argument is NULL, or X_PARSE_ERROR if could not parse the response, or another error returned by redisxCheckRESP()\&. +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "double smaxGetTime (const char * timestamp)" +Returns the a sub-second precision UNIX time value for the given SMA-X timestamp +.PP +\fBParameters\fP +.RS 4 +\fItimestamp\fP The string timestamp returned by SMA-X +.RE +.PP +\fBReturns\fP +.RS 4 +Corresponding UNIX time with sub-second precision, or NAN if the input could not be parsed\&. +.RE +.PP + +.PP +References \fBsmaxParseTime()\fP\&. +.SS "char * smaxGetUnits (const char * table, const char * key)" +Returns the physical unit name, if any, for the given variable\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable / field name in table\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Unit name (e\&.g\&. 'W / Hz'), or NULL or empty string if the variable has no designated physical unit\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetUnits()\fP +.RE +.PP + +.PP +References \fBMETA_UNIT\fP, and \fBsmaxPullMeta()\fP\&. +.SS "int smaxIsConnected ()" +Checks whether SMA-X sharing is currently open (by a preceding call to \fBsmaxConnect()\fP call\&. +.PP +\fBSee also\fP +.RS 4 +\fBsmaxConnect()\fP +.PP +\fBsmaxConnectTo()\fP +.PP +\fBsmaxDisconnect()\fP +.PP +\fBsmaxReconnect()\fP +.RE +.PP + +.SS "boolean smaxIsPipelined ()" +Check if SMA-X is configured with pipeline mode enabled\&. +.PP +\fBReturns\fP +.RS 4 +TRUE (1) if the pipeline is enabled, or else FALSE (0) +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetPipelined()\fP +.RE +.PP + +.SS "boolean smaxIsResilient ()" +Checks whether the resiliency feature has been enabled\&. +.PP +\fBReturns\fP +.RS 4 +TRUE if enabled, otherwise FALSE\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetResilient()\fP +.RE +.PP + +.SS "boolean smaxIsVerbose ()" +Checks id verbose reporting is enabled\&. +.PP +\fBReturns\fP +.RS 4 +TRUE if verbose reporting is enabled, otherwise FALSE\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetVerbose()\fP +.RE +.PP + +.SS "int smaxKeyCount (const char * table)" +Retrieve the current number of variables stored on host (or owner ID)\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The number of keys (fields) in the specified table (>= 0), or an error code (<0), such as: X_NO_INIT if the SMA-X sharing was not initialized, e\&.g\&. via smaConnect()\&. X_GROUP_INVALID if the table name is invalid\&. or one of the errors (<0) returned by redisxRequest()\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxGetKeys()\fP +.RE +.PP + +.SS "int smaxLazyCache (const char * table, const char * key, XType type)" +Specify that a specific variable should be cached for minimum overhead lazy access\&. When a variable is lazy cached its local copy is automatically updated in the background so that accessing it is always nearly instantaneous\&. Lazy caching is a good choice for variables that change less frequently than they are polled typically\&. For variables that change frequently (ans used less frequently), lazy caching is not a great choice since it consumes network bandwidth even when the variable is not being accessed\&. +.PP +Once a variable is lazy cached, it can be accessed instantaneously via \fBsmaxGetLazyCached()\fP without any blocking network operations\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fItype\fP The SMA-X variable type, e\&.g\&. X_FLOAT or X_CHARS(40), of the buffer\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) or X_NO_SERVICE\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxGetLazyCached()\fP +.RE +.PP + +.SS "int smaxLazyEnd (const char * table, const char * key)" +Stops processing lazy updates in the background for a given variable\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyFlush()\fP +.PP +\fBsmaxLazyPull()\fP +.RE +.PP + +.SS "int smaxLazyFlush ()" +Discards caches for all lazy variables (i\&.e\&. stops all subscriptions to variable updates, at least until the next \fBsmaxLazyPull()\fP call)\&. Generally speaking, it's a good idea to call this routine when one is done using a set of lazy variables for the time being, but want to avoid the tedium of calling \fBsmaxLazyEnd()\fP individually for each of them\&. Note however, that after flushing the lazy caches, the fist lazy call following for each variable will inevitably result in a real SMA-X pull\&. So use it carefully! +.PP +\fBReturns\fP +.RS 4 +Number of monitor points flushed\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyPull()\fP +.PP +\fBsmaxLazyEnd()\fP +.RE +.PP + +.PP +References \fBsmaxRemoveSubscribers()\fP\&. +.SS "int smaxLazyPull (const char * table, const char * key, XType type, int count, void * value, \fBXMeta\fP * meta)" +Poll an infrequently changing variable without stressing out the network or the SMA-X database\&. The first lazy pull for a variable will fetch its value from SMA-X and subscribe to update notifications\&. Subsequent \fBsmaxLazyPull()\fP calls to the same variable will retrieve its value from a local cache (without contacting SMA-X) as long as it is unchanged\&. +.PP +Note, after you are done using a variable that has been lazy pulled, you should call \fBsmaxLazyEnd()\fP to signal that it no longer requires to be cached and updated in the background, or call \fBsmaxLazyFlush()\fP to flush all lazy caches for all lazy variables (if that is what you want)\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fItype\fP The SMA-X variable type, e\&.g\&. X_FLOAT or X_CHARS(40), of the buffer\&. +.br +\fIcount\fP The number of points to retrieve into the buffer\&. +.br +\fIvalue\fP Pointer to the buffer to which the data is to be retrieved\&. +.br +\fImeta\fP Pointer to metadata or NULL if no metadata is needed\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) on success, or else an error code (<0) of \fBsmaxPull()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyEnd()\fP +.PP +\fBsmaxLazyFlush()\fP +.PP +\fBsmaxPull()\fP +.PP +\fBsmaxQueue()\fP +.RE +.PP + +.SS "int smaxLazyPullChars (const char * table, const char * key, char * buf, int n)" +Lazy pulls a string value into the specified string buffer\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIbuf\fP Buffer to fill with stored data +.br +\fIn\fP Number of bytes to fill in buffer\&. The retrieved data will be truncated as necessary\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or the error code (<0) returned by \fBsmaxLazyPull()\fP\&. +.RE +.PP + +.PP +References \fBsmaxLazyPull()\fP\&. +.SS "double smaxLazyPullDouble (const char * table, const char * key)" +Returns a single double-precision value for a given SMA-X variable, or NAN if the value could not be retrieved\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The floating-point value stored in SMA-X, or NaN if the value could not be retrieved\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyPullDoubleDefault()\fP +.PP +\fBsmaxPullDouble()\fP +.RE +.PP + +.PP +References \fBsmaxLazyPullDoubleDefault()\fP\&. +.SS "double smaxLazyPullDoubleDefault (const char * table, const char * key, double defaultValue)" +Returns a single double-precision value for a given SMA-X variable, or a default value if the value could not be retrieved\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIdefaultValue\fP The value to return in case of an error\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The floating-point value stored in SMA-X, or the specified default if the value could not be retrieved\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyPullDouble()\fP +.PP +\fBsmaxPullDoubleDefault()\fP +.RE +.PP + +.PP +References \fBsmaxLazyPull()\fP\&. +.SS "long long smaxLazyPullLong (const char * table, const char * key, long long defaultValue)" +Returns a single integer value for a given SMA-X variable, or a default value if the value could not be retrieved\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIdefaultValue\fP The value to return in case of an error\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The long integer value stored in SMA-X, or the specified default if the value could not be retrieved\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxPullLong()\fP +.RE +.PP + +.PP +References \fBsmaxLazyPull()\fP\&. +.SS "char * smaxLazyPullString (const char * table, const char * key)" +Returns a single string value for a given SMA-X variable, or a NULL if the value could not be retrieved\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Pointer to the string value stored in SMA-X, or NULL if the value could not be retrieved\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxPullString()\fP +.RE +.PP + +.PP +References \fBsmaxLazyPull()\fP\&. +.SS "int smaxLazyPullStruct (const char * id, XStructure * s)" +Lazy pulls data into a structure, discarding any prior data that the structure might contain\&. +.PP +\fBParameters\fP +.RS 4 +\fIid\fP Aggregate structure ID\&. +.br +\fIs\fP Destination structure to populate with the retrieved fields +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or the error code (<0) returned by \fBsmaxLazyPull()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxPullStruct()\fP +.PP +xCreateStruct() +.RE +.PP + +.PP +References \fBsmaxLazyPull()\fP\&. +.SS "int smaxParseTime (const char * timestamp, time_t * secs, long * nanosecs)" +Parses a timestamp into broken-down UNIX time\&. +.PP +\fBParameters\fP +.RS 4 +\fItimestamp\fP Timestamp string as returned in redis queries; +.br +\fIsecs\fP Pointer to the returned UNIX time (seconds)\&. +.br +\fInanosecs\fP Pointer to the retuned sub-second remainder as nanoseconds, or NULL if nor requested\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS(0) if the timestamp was successfully parsed\&. X_NULL if there was no timestamp (empty or invalid string), or the \fRsecs\fP argument is NULL\&. X_PARSE_ERROR if the seconds could not be parsed\&. 1 if there was an error parsing the nanosec part\&. X_NULL if the secs arhument is NULL +.RE +.PP + +.SS "int smaxPull (const char * table, const char * key, XType type, int count, void * value, \fBXMeta\fP * meta)" +Pull data from the specified hash table\&. This calls data via the interactive client to Redis\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.br +\fItype\fP SMA-X variable type, e\&.g\&. X_FLOAT or X_CHARS(40), of the buffer\&. +.br +\fIcount\fP Number of points to retrieve into the buffer\&. +.br +\fIvalue\fP Pointer to the buffer to which the data is to be retrieved\&. +.br +\fImeta\fP Pointer to metadata or NULL if no metadata is needed\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized\&. X_GROUP_INVALID if the 'table' argument is invalid\&. X_NAME_INVALID if the 'key' argument is invalid\&. X_NULL if an essential argument is NULL or contains NULL\&. X_NO_SERVICE if there was no connection to the Redis server\&. X_FAILURE if there was an underlying failure\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyPull()\fP +.PP +\fBsmaxQueue()\fP +.RE +.PP + +.SS "double smaxPullDouble (const char * table, const char * key)" +Returns a single floating-point value for a given SMA-X variable, or a NAN if the value could not be retrieved\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The floating-point value stored in SMA-X, or NAN if the value could not be retrieved\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyPullDouble()\fP +.PP +\fBsmaxPullDoubleDefault()\fP +.RE +.PP + +.PP +References \fBsmaxPullDoubleDefault()\fP\&. +.SS "double smaxPullDoubleDefault (const char * table, const char * key, double defaultValue)" +Returns a single floating-point value for a given SMA-X variable, or a specified default value if the SMA-X value could not be retrieved\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.br +\fIdefaultValue\fP The value to return in case of an error\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The floating-point value stored in SMA-X, or the specified default if the value could not be retrieved\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyPullDoubleDefault()\fP +.PP +\fBsmaxPullDouble()\fP +.RE +.PP + +.PP +References \fBsmaxPull()\fP\&. +.SS "double * smaxPullDoubles (const char * table, const char * key, \fBXMeta\fP * meta, int * n)" +Returns a dynamically allocated array of doubles stored in an SMA-X variable\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fImeta\fP (optional) Pointer to metadata to be filled or NULL if not required\&. +.br +\fIn\fP Pointer to which the number of double is returned (if *n > 0) or else an error code\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Pointer to C double[] array containing *n elements, or NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxPullDouble()\fP +.PP +smaxPullFloats() +.RE +.PP + +.SS "int smaxPullInt (const char * table, const char * key, int defaultValue)" +Returns a single integer value for a given SMA-X variable, or a default value if the value could not be retrieved\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIdefaultValue\fP The value to return in case of an error\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The integer value stored in SMA-X, or the specified default if the value could not be retrieved\&. +.RE +.PP +\fBSee also\fP +.RS 4 +smaxLazyPullInt() +.PP +\fBsmaxPullInts()\fP +.PP +smaPullLong() +.RE +.PP + +.PP +References \fBsmaxPull()\fP\&. +.SS "int * smaxPullInts (const char * table, const char * key, \fBXMeta\fP * meta, int * n)" +Returns a dynamically allocated array of integers stored in an SMA-X variable\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fImeta\fP (optional) Pointer to metadata to be filled or NULL if not required\&. +.br +\fIn\fP Pointer to which the number of integers is returned (if *n > 0) or else an error code\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Pointer to C int[] array containing *n elements, or NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +smaxPullShorts() +.PP +\fBsmaxPullLongs()\fP +.PP +\fBsmaxPullInt()\fP +.RE +.PP + +.SS "long long smaxPullLong (const char * table, const char * key, long long defaultValue)" +Returns a single integer value for a given SMA-X variable, or a default value if the value could not be retrieved\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIdefaultValue\fP The value to return in case of an error\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The integer value stored in SMA-X, or the specified default if the value could not be retrieved\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyPullLong()\fP +.PP +\fBsmaxPullLongs()\fP +.PP +\fBsmaxPullInt()\fP +.RE +.PP + +.PP +References \fBsmaxPull()\fP\&. +.SS "long long * smaxPullLongs (const char * table, const char * key, \fBXMeta\fP * meta, int * n)" +Returns a dynamically allocated array of long long (int64) integers stored in an SMA-X variable\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fImeta\fP (optional) Pointer to metadata to be filled or NULL if not required\&. +.br +\fIn\fP Pointer to which the number of integers is returned (if *n > 0) or else an error code\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Pointer to C int[] array containing *n elements, or NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxPullInts()\fP +.PP +smaxPullShorts() +.PP +\fBsmaxPullLong()\fP +.RE +.PP + +.SS "char * smaxPullMeta (const char * meta, const char * table, const char * key, int * status)" +Retrieves a metadata string value for a given variable from the database +.PP +\fBParameters\fP +.RS 4 +\fImeta\fP Root meta table name, usually something like ''\&. +.br +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable / field name in table\&. +.br +\fIstatus\fP Pointer to int in which to return a X_SUCCESS or an error code\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The string metadata value or NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +setPushMeta() +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "char * smaxPullRaw (const char * table, const char * key, \fBXMeta\fP * meta, int * status)" +Returns a dynamically allocated buffer with the raw string value stored in SMA-X\&. This call can also be used to get single string values from SMA-X, since for single string the stored raw value is simply the string itself\&. However, to properly retrieve string arrays, you want to use \fBsmaxPullStrings()\fP instead\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fImeta\fP (optional) Pointer to metadata to be filled or NULL if not required\&. +.br +\fIstatus\fP Pointer int which an error status is returned\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Pointer to C array containing the elements of the specified type, or NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxPullStrings()\fP +.RE +.PP + +.PP +References \fBsmaxPull()\fP\&. +.SS "char * smaxPullString (const char * table, const char * key)" +Returns a single string value for a given SMA-X variable, or a NULL if the value could not be retrieved\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Pouinter to the string value stored in SMA-X, or NULL if the value could not be retrieved\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyPullString()\fP +.PP +\fBsmaxPullStrings()\fP +.RE +.PP + +.PP +References \fBsmaxPull()\fP\&. +.SS "char ** smaxPullStrings (const char * table, const char * key, \fBXMeta\fP * meta, int * n)" +Returns an array of pointers to individuals strings inside the retrieved contiguous data buffer\&. Thus, to discard the returned data after use, you must first discard the underlying buffer (as pointed by the first element) before discarding the array of pointers themselves\&. E\&.g\&.: +.PP +\fR char **array = smaxPullStrings('mygroup', 'myfield', &meta); \&.\&.\&. if(array != NULL) { free(array[0]); // discards the underlying contiguous buffer free(array); // discards the array of pointers\&. } \fP +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fImeta\fP (optional) Pointer to metadata to be filled or NULL if not required\&. +.br +\fIn\fP Pointer to which the number of double is returned (if *n > 0) or else an error code\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Pointer to a an array of strings (char *) containing *n elements, or NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxPullString()\fP +.PP +\fBsmaxPullRaw()\fP +.RE +.PP + +.PP +References \fBsmaxGetMetaCount()\fP, \fBsmaxPullRaw()\fP, \fBXMeta::storeBytes\fP, and \fBX_META_INIT\fP\&. +.SS "XStructure * smaxPullStruct (const char * id, \fBXMeta\fP * meta, int * status)" +Returns a dynamically allocated XStrucure for the specified hashtable in SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fIid\fP Aggregated structure ID\&. +.br +\fImeta\fP (optional) Pointer to metadata to be filled or NULL if not required\&. +.br +\fIstatus\fP Pointer int which an error status is returned\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Pointer to an XStructure, or NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxLazyPullStruct()\fP +.PP +xDestroyStruct() +.RE +.PP + +.PP +References \fBsmaxPull()\fP\&. +.SS "double smaxPullTime (const char * table, const char * key)" +Retrieves the timestamp for a given variable from the database\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name (or NULL if key is an aggregate ID)\&. +.br +\fIkey\fP Variable / field name in table\&. +.RE +.PP +\fBReturns\fP +.RS 4 +(s) UNIX timestamp, as fractional seconds since 1 Jan 1970, or NAN if there was an error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +setPushMeta() +.RE +.PP + +.PP +References \fBSMAX_TIMESTAMPS\fP, and \fBsmaxPullMeta()\fP\&. +.SS "XType smaxPullTypeDimension (const char * table, const char * key, int * ndim, int * sizes)" +Retrieves the timestamp for a given variable from the database\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name (or NULL if key is an aggregate ID)\&. +.br +\fIkey\fP Variable / field name in table\&. +.br +\fIndim\fP Pointer to integer in which to return the dimensionality of the variable, or NULL if not requested\&. +.br +\fIsizes\fP Array to store sizes along each dimension, which should hold X_MAX_DIMS integers, or NULL if dimensions are not requested\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Type of data stored under the specified table/key ID\&. +.RE +.PP +\fBSee also\fP +.RS 4 +setPushMeta() +.RE +.PP + +.PP +References \fBSMAX_DIMS\fP, \fBSMAX_TYPES\fP, \fBsmaxPullMeta()\fP, and \fBsmaxTypeForString()\fP\&. +.SS "int smaxPushMeta (const char * meta, const char * table, const char * key, const char * value)" +Adds/updates metadata associated with an SMA-X variable\&. The data will be pushed via the Redis pipeline channel\&. +.PP +\fBParameters\fP +.RS 4 +\fImeta\fP Root meta table name, usually something like ''\&. +.br +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable / field name in table\&. +.br +\fIvalue\fP Metadata string value\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if the metadata was successfully retrieved X_INCOMPLETE if the meatdata was successfully written but an update notification was not sent or else the return value of redisxSetValue() +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxPullMeta()\fP, redisxSetValue() +.RE +.PP + +.PP +References \fBsmaxGetProgramID()\fP, and \fBsmaxGetRedis()\fP\&. +.SS "int smaxQueue (const char * table, const char * key, XType type, int count, void * value, \fBXMeta\fP * meta)" +Queues a pull requests for pipelined data retrieval\&. Because pipelined pulls are executed on a separate Redis client from the one used for sharing values, e\&.g\&. via \fBsmaxShare()\fP, there is no guarantee as to the order of this pull operation and previously initiated shares from the same thread\&. This would only be an issue if you are trying to use queued read to read back a value you have just shared -- which is not really a good use case anyway, as it generates network traffic for not real reason\&. But, if you must read back a value you have shared, you probably should use a regular \fBsmaxPull()\fP call to ensure ordering\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.br +\fItype\fP SMA-X variable type, e\&.g\&. X_FLOAT or X_CHARS(40), of the buffer\&. +.br +\fIcount\fP Number of points to retrieve into the buffer\&. +.br +\fIvalue\fP Pointer to the buffer to which the data is to be retrieved\&. +.br +\fImeta\fP Pointer to the corresponding metadata structure, or NULL\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful X_NAME_INVALID if the table and key are both NULL X_NULL if the value field is NULL or the return value of xQueue()\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxPull()\fP +.PP +\fBsmaxLazyPull()\fP +.PP +\fBsmaxCreateSyncPoint()\fP +.PP +\fBsmaxQueueCallback()\fP +.RE +.PP + +.PP +References \fBSMAX_PIPE_READ_TIMEOUT_MILLIS\fP\&. +.SS "int smaxQueueCallback (void(*)(void *) f, void * arg)" +Adds a callback function to the queue to be called with the specified argument once all prior requests in the queue have been fullfilled (retrieved from the database)\&. +.PP +As a general rule callbacks added to the pipeline should return very fast, and avoid blocking operations for the most part (using mutexes that may block for very short periods only may be excepted)\&. If the user needs to do more processing, or make blocking calls (e\&.g\&. IO operartions) that may not return for longer periods, the callback should fire off processing in a separate thread, or else simply move the result into another asynchronous processing queue\&. +.PP +\fBParameters\fP +.RS 4 +\fIf\fP The callback function that takes a pointer argument +.br +\fIarg\fP Argument to call the specified function with\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) or else X_NULL if the function parameter is NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxCreateSyncPoint()\fP +.PP +\fBsmaxQueue()\fP +.RE +.PP + +.SS "int smaxReconnect ()" +Reconnects to the SMA-X server\&. It will try connecting repeatedly at regular intervals until the connection is made\&. If resilient mode is enabled, then locally accumulated shares will be sent to the Redis server upon reconnection\&. However, subscriptions are not automatically re-established\&. The caller is responsible for reinstate any necessary subscriptions after the reconnection or via an approproate connection hook\&. +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful X_NO_INIT if SMA-X was never initialized\&. +.RE +.PP +or the error returned by redisxReconnect()\&. +.PP +\fBSee also\fP +.RS 4 +\fBsmaxConnect()\fP +.PP +\fBsmaxConnectTo()\fP +.PP +\fBsmaxDisconnect()\fP +.PP +\fBsmaxIsConnected()\fP +.PP +\fBsmaxSetResilient()\fP +.PP +\fBsmaxAddConnectHook()\fP +.RE +.PP + +.PP +References \fBSMAX_RECONNECT_RETRY_SECONDS\fP\&. +.SS "int smaxReleaseWaits ()" +Unblocks all smax_wait*() calls, which will return X_REL_PREMATURE, as a result\&. +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxWaitOnAnySubscribed()\fP +.RE +.PP + +.PP +References \fBRELEASEID\fP\&. +.SS "int smaxRemoveConnectHook (void(*)(void) setupCall)" +Remove a post-connection callback function\&. It's a wrapper to redisxRemoveConnectHook()\&. +.PP +\fBParameters\fP +.RS 4 +\fIsetupCall\fP Callback function +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) or an error code (<0) from redisxAddConnectHook()\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxAddConnectHook()\fP +.PP +\fBsmaxConnect()\fP +.PP +\fBsmaxConnectTo()\fP +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "int smaxRemoveDisconnectHook (void(*)(void) cleanupCall)" +Remove a post-cdisconnect callback function\&. It's a wrapper to redisxRemiveDisconnectHook()\&. +.PP +\fBParameters\fP +.RS 4 +\fIcleanupCall\fP Callback function +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) or an error code (<0) from redisxAddConnectHook()\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxAddDisconnectHook()\fP +.PP +\fBsmaxDisconnect()\fP +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "int smaxRemoveMessageProcessor (int id)" +Stops a running message processor\&. +.PP +\fBParameters\fP +.RS 4 +\fIid\fP Message processor ID, as returned by \fBsmaxAddMessageProcessor()\fP +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NULL if no message processor is running by that ID\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxAddMessageProcessor()\fP +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "int smaxRemoveSubscribers (RedisSubscriberCall f)" +Remove all instances of a subscriber callback function from the current list of functions processing PUB/SUB messages\&. This call only deactivates the callback routine, but does not stop the delivery of update notifications from the Redis server\&. You should therefore also call \fBsmaxUnsubscribe()\fP as appropriate to stop notifications for variables that no longer have associated callbacks\&. +.PP +\fBParameters\fP +.RS 4 +\fIf\fP Function to remove +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or else an error (<0) returned by redisxRemoveSubscriber()\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxUnsubscribe()\fP +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "void smaxResetMeta (\fBXMeta\fP * m)" +Set metadata to their default values\&. After resetting the supplied metadata will have exactly the same content as if it were initialized with the X_META_INIT macro\&. +.PP +\fBParameters\fP +.RS 4 +\fIm\fP Pointer to the metadata that is to be cleared\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBX_META_INIT\fP +.RE +.PP + +.PP +References \fBX_META_INIT\fP\&. +.SS "int smaxSendDebug (const char * msg)" +Broadcast a debugging message via SMA-X (e\&.g\&. program traces)\&. +.PP +\fBParameters\fP +.RS 4 +\fImsg\fP Message text +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an X error\&. +.RE +.PP + +.PP +References \fBSMAX_MSG_DEBUG\fP\&. +.SS "int smaxSendDetail (const char * msg)" +Broadcast non-essential verbose informational detail via SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fImsg\fP Message text +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an X error\&. +.RE +.PP + +.PP +References \fBSMAX_MSG_DETAIL\fP\&. +.SS "int smaxSendError (const char * msg)" +Broadcast an error message via SMA-X\&. Errors should be used for an issues that impair program functionality\&. +.PP +\fBParameters\fP +.RS 4 +\fImsg\fP Message text +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an X error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSendWarning()\fP; +.PP +\fBsmaxSendDebug()\fP; +.RE +.PP + +.PP +References \fBSMAX_MSG_ERROR\fP\&. +.SS "int smaxSendInfo (const char * msg)" +Broadcast an informational message via SMA-X\&. These should be confirmations or essential information reported back to users\&. Non-essential information should be sent with sendDetail() instead\&. +.PP +\fBParameters\fP +.RS 4 +\fImsg\fP Message text +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an X error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +sendDetail() +.PP +sendStatus() +.RE +.PP + +.PP +References \fBSMAX_MSG_INFO\fP\&. +.SS "int smaxSendProgress (double fraction, const char * msg)" +Broadcast a progress update over SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fIfraction\fP (0\&.0:1\&.0) Completion fraction\&. +.br +\fImsg\fP Message text +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an X error\&. +.RE +.PP + +.PP +References \fBSMAX_MSG_DETAIL\fP\&. +.SS "int smaxSendStatus (const char * msg)" +Broadcast a program status update via SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fImsg\fP Message text +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an X error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +sendInfo() +.RE +.PP + +.PP +References \fBSMAX_MSG_STATUS\fP\&. +.SS "int smaxSendWarning (const char * msg)" +Broadcast a warning message via SMA-X\&. Warnings should be used for any potentially problematic issues that nonetheless do not impair program functionality\&. +.PP +\fBParameters\fP +.RS 4 +\fImsg\fP Message text +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an X error\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSendError()\fP; +.PP +\fBsmaxSendDebug()\fP; +.RE +.PP + +.PP +References \fBSMAX_MSG_WARNING\fP\&. +.SS "int smaxSetAuth (const char * username, const char * password)" +Sets the SMA-X database authentication parameters (if any) before connecting to the SMA-X server\&. +.PP +\fBParameters\fP +.RS 4 +\fIusername\fP Redis ACL user name (if any), or NULL for no user-based authentication +.br +\fIpassword\fP Redis database password (if any), or NULL if the database is not password protected +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_ALREADY_OPEN if cannot alter the server configuration because we are already in a connected state\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetServer()\fP +.PP +\fBsmaxConnect()\fP +.RE +.PP + +.PP +References \fBsmaxIsConnected()\fP\&. +.SS "int smaxSetCoordinateAxis (const char * id, int n, const \fBXCoordinateAxis\fP * axis)" +Defines the n'th coordinate axis for a given SMA-X coordinate system table id\&. +.PP +\fBParameters\fP +.RS 4 +\fIid\fP Fully qualified SMA-X coordinate system ID\&. +.br +\fIn\fP The (0-based) index of the coordinate axis +.br +\fIaxis\fP Pointer to the structure describing the coordinate axis\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if the coordinate axis was successfully set in the database\&. or else the return value of redisxMultiSet()\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetCoordinateAxis()\fP, redisxMultiSet() +.RE +.PP + +.PP +References \fBXCoordinateAxis::name\fP, \fBXCoordinateAxis::refIndex\fP, \fBXCoordinateAxis::refValue\fP, \fBsmaxGetRedis()\fP, \fBXCoordinateAxis::step\fP, and \fBXCoordinateAxis::unit\fP\&. +.SS "int smaxSetCoordinateSystem (const char * table, const char * key, const \fBXCoordinateSystem\fP * coords)" +Sets the coordinate system metadata for data in the database\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable / field name in table\&. +.br +\fIcoords\fP Pointer to the coordinate system structure associated to this variable\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if the coordinate system was successfully sent to SMA-X or else the first error encountered by xSetCoordinateAxis() +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxGetCoordinateSystem()\fP +.PP +\fBsmaxSetCoordinateAxis()\fP +.RE +.PP + +.PP +References \fBXCoordinateSystem::axis\fP, \fBMETA_COORDS\fP, \fBXCoordinateSystem::nAxis\fP, and \fBsmaxSetCoordinateAxis()\fP\&. +.SS "int smaxSetDB (int idx)" +Sets a non-default Redis database index to use for SMA-X before connecting to the SMA-X server\&. +.PP +\fBParameters\fP +.RS 4 +\fIidx\fP The Redis database index to use (if not the default one) +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_ALREADY_OPEN if cannot alter the server configuration because we are already in a connected state\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetServer()\fP +.PP +\fBsmaxConnect()\fP +.RE +.PP + +.PP +References \fBsmaxIsConnected()\fP\&. +.SS "int smaxSetDescription (const char * table, const char * key, const char * description)" +Sets the static description for a given SMA-X variable\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable / field name in table\&. +.br +\fIdescription\fP Concise but descriptive summary of the meaning of the variable\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) If successful or else the return value of \fBsmaxPushMeta()\fP +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetDescription()\fP, \fBsmaxPushMeta()\fP +.RE +.PP + +.PP +References \fBMETA_DESCRIPTION\fP, and \fBsmaxPushMeta()\fP\&. +.SS "void smaxSetHostName (const char * name)" +Changes the host name to the user-specified value instead of the default (leading component of the value returned by gethostname())\&. Subsequent calls to \fBsmaxGetHostName()\fP will return the newly set value\&. An argument of NULL resets to the default\&. +.PP +\fBParameters\fP +.RS 4 +\fIname\fP the host name to use, or NULL to revert to the default (leading component of gethostname())\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxGetHostName()\fP +.RE +.PP + +.SS "int smaxSetMaxPendingPulls (int n)" +Configures how many pull requests can be queued in when piped pulls are enabled\&. If the queue reaches the specified limit, no new pull requests can be submitted until responses arrive, draining the queue somewhat\&. +.PP +\fBParameters\fP +.RS 4 +\fIn\fP The maximum number of pull requests that can be queued\&. +.RE +.PP +\fBReturns\fP +.RS 4 +TRUE if the argument was valid, and the queue size was set to it, otherwise FALSE +.RE +.PP + +.SS "void smaxSetMessageSenderID (const char * id)" +Sets the sender ID for outgoing program messages\&. By default the sender ID is : for the program that calls this function, but it can be modified to use some other SMA-X style hierarchical ID also\&. +.PP +\fBParameters\fP +.RS 4 +\fIid\fP The new sender ID for outgoing program messages, or NULL to reinstate the default : style ID\&. The argument is not referenced and can be deallocated as desired after the call without affecting the newly defined message ID\&. +.RE +.PP + +.SS "void smaxSetOrigin (\fBXMeta\fP * m, const char * origin)" +Sets the 'origin' field of an SMA-X metadata to the specified value, truncating as necessary to fit into the allotted fixed storage\&. +.PP +\fBParameters\fP +.RS 4 +\fIorigin\fP The origination information, usually as hostname:progname +.br +\fIm\fP Pointer to metadata to set\&. +.RE +.PP + +.PP +References \fBXMeta::origin\fP, and \fBSMAX_ORIGIN_LENGTH\fP\&. +.SS "int smaxSetPipelineConsumer (void(*)(RESP *) f)" +Change the pipeline response consumer function (from it's default or other previous consumer)\&. It is a wrapper for redisxSetPipelineConsumer()\&. +.PP +\fBParameters\fP +.RS 4 +\fIf\fP The function to process ALL pipeline responses from Redis\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or else an error by redisxSetPipelineConsumer() +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetPipelined()\fP +.PP +\fBsmaxIsPipelined()\fP +.RE +.PP + +.PP +References \fBsmaxGetRedis()\fP\&. +.SS "int smaxSetPipelined (boolean isEnabled)" +Enable or disable pipelined write operations (enabled by default)\&. When pipelining, share calls will return as soon as the request is sent to the Redis server, without waiting for a response\&. Instead, responses are consumed asynchronously by a dedicated thread, which will report errors to stderr\&. Pipelined writes can have a significant performance advantage over handshaking at the cost of one extra socket connection to Redis (dedicated to pipelining) and the extra thread consuming responses\&. +.PP +The default state of pipelined writes might vary by platform (e\&.g\&. enabled on Linux, disabled on LynxOS)\&. +.PP +\fBIMPORTANT\fP: calls to \fBsmaxSetPipelined()\fP must precede the call to \fBsmaxConnect()\fP\&. +.PP +\fBParameters\fP +.RS 4 +\fIisEnabled\fP TRUE to enable pipelined writes, FALSE to disable (default is enabled)\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_ALREADY_OPEN if cannot alter the server configuration because we are already in a connected state\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxIsPipelined()\fP +.PP +\fBsmaxSetPipelineConsumer()\fP +.RE +.PP + +.PP +References \fBsmaxIsConnected()\fP\&. +.SS "void smaxSetResilient (boolean value)" +Enables the resiliency feature of the library, which keeps track of local changes destined to the database when the database is not reachable, and sending all locally stored updates once the database comes online again\&. However, after sending all pending updates to the remote server, the program may exit (default behavior), unless \fBsmaxSetResilientExit()\fP is set to FALSE (0), so that it can be restarted in a fresh state, setting up subscriptions and scripts again as necessary\&. +.PP +\fBParameters\fP +.RS 4 +\fIvalue\fP TRUE (non-zero) to enable, or FALSE (0) to disable resiliency\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxIsResilient()\fP +.PP +\fBsmaxSetResilientExit()\fP +.RE +.PP + +.PP +References \fBsmaxAddConnectHook()\fP, and \fBsmaxRemoveConnectHook()\fP\&. +.SS "void smaxSetResilientExit (boolean value)" +Sets whether the program should exit in resilient mode, after having pushed all local updates\&. The default is to exit since the reconnecting in resilient mode does not by itself re-establish existing subscriptions\&. However, when subscriptions aren't used, or if they are set up as a connect hook, the user may want the program to simply continue\&. This is possible by passing FALSE (0) as the argument to this call\&. This setting only takes effect when resilient mode is enabled\&. Otherwise, the exit policy is set by the RedisX library\&. +.PP +\fBParameters\fP +.RS 4 +\fIvalue\fP Whether to exit the program after all local updates have been pushed to SMA-X after a recovering from an outage\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetResilient()\fP +.PP +\fBsmaxAddConnectHook()\fP +.RE +.PP + +.SS "int smaxSetServer (const char * host, int port)" +Configures the SMA-X server before connecting\&. +.PP +\fBParameters\fP +.RS 4 +\fIhost\fP The SMA-X REdis server host name or IP address\&. +.br +\fIport\fP The Redis port number on the SMA-X server, or <=0 to use the default +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_ALREADY_OPEN if cannot alter the server configuration because we are already in a connected state\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSetAuth()\fP +.PP +\fBsmaxSetDB()\fP +.PP +\fBsmaxConnect()\fP +.RE +.PP + +.PP +References \fBsmaxIsConnected()\fP\&. +.SS "int smaxSetTcpBuf (int size)" +Set the size of the TCP/IP buffers (send and receive) for future client connections\&. +.PP +\fBParameters\fP +.RS 4 +\fIsize\fP (bytes) requested buffer size, or <= 0 to use default value +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxConnect\fP; +.RE +.PP + +.PP +References \fBsmaxIsConnected()\fP\&. +.SS "int smaxSetUnits (const char * table, const char * key, const char * unit)" +Sets the physical unit name for a given SMA-X variable\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable / field name in table\&. +.br +\fIunit\fP Standard unit specification, e\&.g\&. 'W / Hz' or 'W Hz**{-1}'\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) If successful or else the return value of \fBsmaxPushMeta()\fP +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxGetUnits()\fP, \fBsmaxPushMeta()\fP +.RE +.PP + +.PP +References \fBMETA_UNIT\fP, and \fBsmaxPushMeta()\fP\&. +.SS "void smaxSetVerbose (boolean value)" +Enable or disable verbose reporting of all SMA-X operations (and possibly some details of them)\&. Reporting is done on the standard output (stdout)\&. It may be useful when debugging programs that use the SMA-X interface\&. Verbose reporting is DISABLED by default\&. +.PP +\fBParameters\fP +.RS 4 +\fIvalue\fP TRUE to enable verbose reporting, or FALSE to disable\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxIsVerbose()\fP +.RE +.PP + +.SS "int smaxShare (const char * table, const char * key, const void * value, XType type, int count)" +Share the data into a Redis hash table over the interactive Redis client\&. It's a fire-and-forget type implementation, which sends the data to Redis, without waiting for confirmation of its arrival\&. The choice improves the efficiency and throughput, and minimizes execution time, of the call, but it also means that a pipelined pull request in quick succession, e\&.g\&. via \fBsmaxQueue()\fP, may return a value on the pipeline client \fIbefore\fP this call is fully executed on the interactive Redis client\&. +.PP +(It is generally unlikely that you will follow this share call with a pipelined pull of the same variable\&. It would not only create superflous network traffic for no good reason, but it also would have unpredictable results\&. So, don't\&.) +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name in which to share entry\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.br +\fIvalue\fP Pointer to the buffer whose data is to be shared\&. +.br +\fItype\fP SMA-X variable type, e\&.g\&. X_FLOAT or X_CHARS(40), of the buffer\&. +.br +\fIcount\fP Number of 1D elements\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized\&. X_GROUP_INVALID if the table name is invalid\&. X_NAME_INVALID if the 'key' argument is invalid\&. X_SIZE_INVALID if count < 1 or count > X_MAX_ELEMENTS X_NULL if the 'value' argument is NULL\&. X_NO_SERVICE if there was no connection to the Redis server\&. X_FAILURE if there was an underlying failure\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareArray()\fP +.PP +\fBsmaxShareField()\fP +.PP +\fBsmaxShareStruct()\fP +.RE +.PP + +.PP +References \fBsmaxShareArray()\fP\&. +.SS "int smaxShareArray (const char * table, const char * key, const void * ptr, XType type, int ndim, const int * sizes)" +Share a multidimensional array, such as an \fRint[][][]\fP, or \fRfloat[][]\fP, in a single atomic transaction\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table in which to write entry\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.br +\fIptr\fP Pointer to the data buffer, such as an \fRint[][][]\fP or \fRfloat[][]\fP\&. +.br +\fItype\fP SMA-X variable type, e\&.g\&. X_FLOAT or X_CHARS(40), of the buffer\&. +.br +\fIndim\fP Dimensionality of the data (0 <= \fRndim\fP <= X_MAX_DIMS)\&. +.br +\fIsizes\fP An array of ints containing the sizes along each dimension\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized\&. X_GROUP_INVALID if the table name is invalid\&. X_NAME_INVALID if the 'key' argument is invalid\&. X_SIZE_INVALID if ndim or sizes are invalid\&. X_NULL if the 'value' argument is NULL\&. X_NO_SERVICE if there was no connection to the Redis server\&. X_FAILURE if there was an underlying failure\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShare()\fP +.RE +.PP + +.PP +References \fBsmaxShareField()\fP, and \fBsmaxValuesToString()\fP\&. +.SS "int smaxShareBoolean (const char * table, const char * key, boolean value)" +Shares a single boolean value to SMA-X\&. All non-zero values are mapped to '1'\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIvalue\fP A boolean value\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareBooleans()\fP +.RE +.PP + +.PP +References \fBsmaxShareBooleans()\fP\&. +.SS "int smaxShareBooleans (const char * table, const char * key, const boolean * values, int n)" +Shares an array of boolean values to SMA-X\&. All non-zero values are mapped to '1'\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.br +\fIvalues\fP Pointer to boolean[] array\&. +.br +\fIn\fP Number of elements in array to share\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareBoolean()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxShareBytes (const char * table, const char * key, const char * values, int n)" +Shares a binary sequence to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIvalues\fP pointer to the byte buffer\&. +.br +\fIn\fP Number of bytes in buffer to share\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareShorts()\fP +.PP +\fBsmaxShareInts()\fP +.PP +\fBsmaxShareLongs()\fP +.PP +\fBsmaxShareInt()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxShareDouble (const char * table, const char * key, double value)" +Shares a single floating point value to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIvalue\fP floating-point value\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareDoubles()\fP +.PP +\fBsmaxShareFloats()\fP +.RE +.PP + +.PP +References \fBsmaxShareDoubles()\fP\&. +.SS "int smaxShareDoubles (const char * table, const char * key, const double * values, int n)" +Shares an array of doubles to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIvalues\fP Pointer to double[] array\&. +.br +\fIn\fP Number of elements in array to share\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareDouble()\fP +.PP +\fBsmaxShareFloats()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxShareField (const char * table, const XField * f)" +Share a field object, which may contain any SMA-X data type\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table in which to write entry\&. +.br +\fIf\fP Pointer for XField holding the data to share\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized\&. X_GROUP_INVALID if the table name is invalid\&. X_NAME_INVALID if the 'key' argument is invalid\&. X_SIZE_INVALID if ndim or sizes are invalid\&. X_NULL if the 'value' argument is NULL\&. X_NO_SERVICE if there was no connection to the Redis server\&. X_FAILURE if there was an underlying failure\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShare()\fP +.PP +\fBsmaxShareField()\fP +.PP +\fBsmaxShareStruct()\fP +.PP +xSetField() +.PP +xGetField() +.RE +.PP + +.PP +References \fBsmaxShareStruct()\fP\&. +.SS "int smaxShareFloats (const char * table, const char * key, const float * values, int n)" +Shares an array of floats to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIvalues\fP Pointer to float[] array\&. +.br +\fIn\fP Number of elements in array to share\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareDouble()\fP +.PP +\fBsmaxShareDoubles()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxShareHex (const char * table, const char * key, long long value)" +Shares a single integer value to SMA-X in a hexadecimal representatin\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIvalue\fP Integer value\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareInt()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxShareInt (const char * table, const char * key, long long value)" +Shares a single integer value to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name\&. +.br +\fIkey\fP Variable name under which the data is stored\&. +.br +\fIvalue\fP Integer value\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareHex()\fP +.PP +\fBsmaxShareInts()\fP +.RE +.PP + +.PP +References \fBsmaxShareLongs()\fP\&. +.SS "int smaxShareInts (const char * table, const char * key, const int * values, int n)" +Shares an array of long integers to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIvalues\fP Pointer to int[] array\&. +.br +\fIn\fP Number of elements in array to share\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareLongs()\fP +.PP +\fBsmaxShareShorts()\fP +.PP +\fBsmaxShareBytes()\fP +.PP +\fBsmaxShareInt()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxShareLongs (const char * table, const char * key, const long long * values, int n)" +Shares an array of wide integers to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIvalues\fP Pointer to long long[] array\&. +.br +\fIn\fP Number of elements in array to share\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareInts()\fP +.PP +\fBsmaxShareShorts()\fP +.PP +\fBsmaxShareBytes()\fP +.PP +\fBsmaxShareInt()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxShareShorts (const char * table, const char * key, const short * values, int n)" +Shares an array of shorts to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIvalues\fP Pointer to short[] array\&. +.br +\fIn\fP Number of elements in array to share\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS(0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareInt()\fP +.PP +\fBsmaxShareBytes()\fP +.PP +\fBsmaxShareInts()\fP +.PP +\fBsmaxShareLongs()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxShareString (const char * table, const char * key, const char * sValue)" +Shares a single string value to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIsValue\fP Pointer to string\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareStrings()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxShareStrings (const char * table, const char * key, const char ** sValues, int n)" +Shares an array of strings to SMA-X\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP The hash table name\&. +.br +\fIkey\fP The variable name under which the data is stored\&. +.br +\fIsValues\fP Pointer to array of string pointers\&. +.br +\fIn\fP Number of elements in array to share\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0), or else an appropriate error code (<0) from \fBsmaxShare()\fP\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShareString()\fP +.RE +.PP + +.PP +References \fBsmaxShare()\fP\&. +.SS "int smaxShareStruct (const char * id, const XStructure * s)" +Share a structure, and all its data including recursive sub-structures, in a single atromic transaction\&. +.PP +\fBParameters\fP +.RS 4 +\fIid\fP Structure's ID, i\&.e\&. its own aggregated hash table name\&. +.br +\fIs\fP Pointer to the structure data\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NO_INIT if the SMA-X library was not initialized\&. X_GROUP_INVALID if the table name is invalid\&. X_NAME_INVALID if the 'key' argument is invalid\&. X_NULL if the 'value' argument is NULL\&. X_NO_SERVICE if there was no connection to the Redis server\&. X_FAILURE if there was an underlying failure\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxShare()\fP +.PP +\fBsmaxShareField()\fP +.PP +xCreateStruct() +.RE +.PP + +.PP +References \fBsmaxCreateField()\fP\&. +.SS "int smaxStringToValues (const char * str, void * value, XType type, int eCount, int * pos)" +Deserializes a string to binary values\&. +.PP +\fBParameters\fP +.RS 4 +\fIstr\fP Serialized ASCII representation of the data (as stored by Redis)\&. +.br +\fIvalue\fP Pointer to the buffer that will hold the binary values\&. The caller is responsible for ensuring the buffer is sufficiently sized for holding the data for the given variable\&. +.br +\fItype\fP Share type, e\&.g\&. X_INT\&. The types X_RAW, X_STRUCT are not supported by this function\&. +.br +\fIeCount\fP Number of elements to retrieve\&. Ignored for X_STRUCT\&. +.br +\fIpos\fP Parse position, i\&.e\&. the number of characters parsed from the input string\&.\&.\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Number of elements successfully parsed, or a negative error code: +.PP +.nf + X_NULL If the value or str argument is NULL\&. + X_TYPE_INVALID If the type is not supported\&. + X_SIZE_INVALID If size is invalid (e\&.g\&. X_RAW, X_STRUCT) + X_PARSE_ERROR If the tokens could not be parsed in the format expected + +.fi +.PP + +.RE +.PP + +.PP +References \fBsmaxUnpackStrings()\fP\&. +.SS "char * smaxStringType (XType type)" +Returns the string type for a given XType argument as a constant expression\&. For examples X_LONG -> 'int64'\&. +.PP +\fBParameters\fP +.RS 4 +\fItype\fP SMA-X type, e\&.g\&. X_FLOAT +.RE +.PP +\fBReturns\fP +.RS 4 +Corresponding string type, e\&.g\&. 'float'\&. (Default is 'string' -- since typically anything can be represented as strings\&.) +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxTypeForString()\fP +.RE +.PP + +.SS "int smaxSubscribe (const char * table, const char * key)" +Subscribes to a specific key(s) in specific group(s)\&. Both the group and key names may contain Redis subscription patterns, e\&.g\&. '*' or '?', or bound characters in square-brackets, e\&.g\&. '[ab]'\&. The subscription only enables receiving update notifications from Redis for the specified variable or variables\&. After subscribing, you can either wait on the subscribed variables to change, or add callback functions to process subscribed variables changes, via \fBsmaxAddSubscriber()\fP\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Variable group pattern, i\&.e\&. hash-table names\&. (NULL is the same as '*')\&. +.br +\fIkey\fP Variable name pattern\&. (if NULL then subscribes only to the table stem)\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS if successfully subscribed to the Redis distribution channel\&. X_NO_SERVICE if there is no active connection to the Redis server\&. X_NULL if the channel argument is NULL X_NO_INIT if the SMA-X library was not initialized\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxUnsubscribe()\fP +.PP +\fBsmaxWaitOnSubscribed()\fP +.PP +\fBsmaxWaitOnSubscribedGroup()\fP +.PP +\fBsmaxWaitOnSubscribedVar()\fP +.PP +\fBsmaxWaitOnAnySubscribed()\fP +.PP +\fBsmaxAddSubscriber()\fP +.RE +.PP + +.SS "int smaxSync (\fBXSyncPoint\fP * sync, int timeoutMillis)" +Waits for the queue to reach the specified sync point, up to an optional timeout limit\&. +.PP +\fBParameters\fP +.RS 4 +\fIsync\fP Pointer to a queued synchronization point\&. +.br +\fItimeoutMillis\fP An optional timeout in milliseconds\&. When set to a positive value The call will be guaranteed to return in the specified interval, whether or not the pipelined reads all succeeded\&. The return value can be used to check for errors or if the call timed out before all data were collected\&. If X_TIMEDOUT is returned, smax_end_bulk_pulls() may be called again to allow more time for the queued read operations to complete\&. 0 or negative timeout values will cause the call to wait indefinitely until reads are complete\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if all reads have completed successfully, or the first read error that was enountered (e\&.g\&. RM_INVALID_KEY), or: X_TIMEDOUT if the call timed out while still awaiting data for the queued read requests\&. X_NULL if the SyncPoint argument is NULL, or its mutex/condition field have not been initialized\&. X_FAILURE if the SyncPoint's mutex has not been initialized\&. +.RE +.PP +or the first pull error encountered in the queue since the current batch began\&. +.PP +\fBSee also\fP +.RS 4 +\fBsmaxCreateSyncPoint()\fP +.PP +\fBsmaxWaitQueueComplete()\fP +.RE +.PP + +.PP +References \fBXSyncPoint::isComplete\fP, \fBXSyncPoint::lock\fP, and \fBXSyncPoint::status\fP\&. +.SS "int smaxTimestamp (char * buf)" +Prints the current time into the supplied buffer with subsecond precision\&. +.PP +\fBParameters\fP +.RS 4 +\fIbuf\fP Pointer to string buffer, must be at least X_TIMESTAMP_LENGTH in size\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Number of characters printed, not including the terminating '\\0', or else an error code (<0) if the \fRbuf\fP argument is NULL\&. +.RE +.PP + +.PP +References \fBsmaxTimeToString()\fP\&. +.SS "int smaxTimeToString (const struct timespec * time, char * buf)" + +.PP +*/ Prints the given UNIX time into the supplied buffer with subsecond precision\&. +.PP +\fBParameters\fP +.RS 4 +\fItime\fP Pointer to time value\&. +.br +\fIbuf\fP Pointer to string buffer, must be at least X_TIMESTAMP_LENGTH in size\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Number of characters printed, not including the terminating '\\0', or else an error code (<0) if the \fRbuf\fP argument is NULL\&. +.RE +.PP + +.SS "XType smaxTypeForString (const char * type)" +Returns the XType for a given case-sensitive type string\&. For example 'float' -> X_FLOAT\&. The value 'raw' will return X_RAW\&. +.PP +\fBParameters\fP +.RS 4 +\fItype\fP String type, e\&.g\&. 'struct'\&. +.RE +.PP +\fBReturns\fP +.RS 4 +Corresponding XType, e\&.g\&. X_STRUCT\&. (The default return value is X_RAW, since all Redis values can be represented as raw strings\&.) +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxStringType()\fP +.RE +.PP + +.SS "int smaxUnpackStrings (const char * data, int len, int count, char ** dst)" +Returns an array of dynamically allocated strings from a packed buffer of consecutive 0-terminated or '\\r'-separated string elements\&. +.PP +\fBParameters\fP +.RS 4 +\fIdata\fP Pointer to the packed string data buffer\&. +.br +\fIlen\fP length of packed string (excl\&. termination)\&. +.br +\fIcount\fP Number of string elements expected\&. If fewer than that are found in the packed data, then the returned array of pointers will be padded with NULL\&. +.br +\fIdst\fP An array of string pointers (of size 'count') which will point to dynamically allocated string (char*) elements\&. The array is assumed to be uninitialized, and elements will be allocated as necessary\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NULL if one of the argument pointers is NULL, or else X_INCOMPLETE if some of the components were too large to unpack (alloc error)\&. +.RE +.PP + +.SS "int smaxUnsubscribe (const char * table, const char * key)" +Unsubscribes from a specific key(s) in specific group(s)\&. Both the group and key names may contain Redis subscription patterns, e\&.g\&. '*' or '?', or bound characters in square-brackets, e\&.g\&. '[ab]'\&. Unsubscribing will only stops the delivery of update notifications for the affected varuiables, but does not deactivate the associated callbacks for these added via \fBsmaxAddSubscriber()\fP\&. Therefore you should also call smaxRemovesubscribers() as appropriate to deactivate actions that can no longer get triggered by updates\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Variable group pattern, i\&.e\&. structure or hash-table name(s) (NULL is the same as '*')\&. +.br +\fIkey\fP Variable name pattern\&. (if NULL then unsubscribes only from the table stem)\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS if successfully unsubscribed to the Redis distribution channel\&. X_NO_SERVICE if there is no active connection to the Redis server\&. X_NULL if the channel argument is NULL X_NO_INIT if the SMA-X library was not initialized\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSubscribe()\fP +.PP +\fBsmaxRemoveSubscribers()\fP +.RE +.PP + +.SS "char * smaxValuesToString (const void * value, XType type, int eCount, char * trybuf, int trylength)" +Serializes binary values into a string representation (for Redis)\&. +.PP +\fBParameters\fP +.RS 4 +\fIvalue\fP Pointer to an array of values, or NULL to produce all zeroes\&. If type is X_STRING value should be a pointer to a char** (array of string pointers), as opposed to X_CHAR(n), which expects a contiguous char* buffer with [n * eCount] length (Note, a char[eCount][n] is equivalent to such a char* buffer)\&. +.br +\fItype\fP Share type, e\&.g\&. X_DOUBLE\&. All type except X_STRUCT are supported\&. +.br +\fIeCount\fP Number of elements (ignored for X_RAW)\&. +.br +\fItrybuf\fP (optional) An optional pointer to a buffer that will be used if sufficient (can be NULL)\&. +.br +\fItrylength\fP (optional) Size of the optional buffer\&. +.RE +.PP +\fBReturns\fP +.RS 4 +The pointer to the string buffer holding the ASCII values\&. It may be the supplied buffer (if sufficient), the input value (if type is X_RAW) or else a dynamically allocated buffer, or NULL if the key is malformed\&. If the returned value is neither the input value nor trybuf, then the caller is responsible for calling free() on the dynamically allocated buffer after use\&. +.RE +.PP + +.SS "int smaxWaitOnAnySubscribed (char ** changedTable, char ** changedKey, int timeout)" +Waits until any variable was pushed on any host, returning both the host and variable name for the updated value\&. The variable must be already subscribed to with \fBsmaxSubscribe()\fP, or else the wait will not receive update notifications\&. +.PP +\fBParameters\fP +.RS 4 +\fIchangedTable\fP Pointer to the variable that points to the string buffer for the returned table name or NULL\&. The lease of the buffer is for the call only\&. +.br +\fIchangedKey\fP Pointer to the variable that points to the string buffer for the returned variable name or NULL\&. The lease of the buffer is for the call only\&. +.br +\fItimeout\fP (s) Timeout value\&. 0 or negative values result in an indefinite wait\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if a variable was pushed on a host\&. X_NO_INIT if the SMA-X sharing was not initialized via \fBsmaxConnect()\fP\&. X_NO_SERVICE if the connection was broken X_GROUP_INVALID if the buffer for the returned table name is NULL\&. X_NAME_INVALID if the buffer for the returned variable name is NULL\&. X_INTERRUPTED if \fBsmaxReleaseWaits()\fP was called\&. X_INCOMPLETE if the wait timed out\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSubscribe()\fP +.PP +\fBsmaxWaitOnSubscribed()\fP +.PP +\fBsmaxWaitOnSubscribedGroup()\fP +.PP +\fBsmaxReleaseWaits()\fP +.RE +.PP + +.PP +References \fBRELEASEID\fP, and \fBsmaxIsConnected()\fP\&. +.SS "int smaxWaitOnSubscribed (const char * table, const char * key, int timeout)" +Waits for a specific pushed entry\&. There must be an active subscription that includes the specified group & variable, or else the call will block indefinitely\&. +.PP +\fBParameters\fP +.RS 4 +\fItable\fP Hash table name +.br +\fIkey\fP Variable name to wait on\&. +.br +\fItimeout\fP (s) Timeout value\&. 0 or negative values result in an indefinite wait\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if the variable was updated on some host (or owner)\&. X_NO_INIT if the SMA-X sharing was not initialized via \fBsmaxConnect()\fP\&. X_GROUP_INVALID if the 'group' argument is NULL; X_NAME_INVALID if the 'key' argument is NULL\&. X_REL_PREMATURE if \fBsmaxReleaseWaits()\fP was called\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSubscribe()\fP +.PP +\fBsmaxWaitOnSubscribed()\fP +.PP +\fBsmaxWaitOnSubscribedGroup()\fP +.PP +\fBsmaxWaitOnSubscribedVar()\fP +.PP +\fBsmaxWaitOnAnySubscribed()\fP +.PP +\fBsmaxReleaseWaits()\fP +.RE +.PP + +.SS "int smaxWaitOnSubscribedGroup (const char * matchTable, char ** changedKey, int timeout)" +Waits for changes on a specific group\&. The must be an active subscription including that group, or else the call will block indefinitely\&. +.PP +\fBParameters\fP +.RS 4 +\fImatchTable\fP Hash table name (e\&.g\&. owner ID) to wait on\&. +.br +\fIchangedKey\fP Pointer to the string that holds the name of the variable which unblocked the wait or which is set to NULL\&. The lease of the buffer is for the call only\&. The caller should copy its content if persistent storage is required\&. +.br +\fItimeout\fP (s) Timeout value\&. 0 or negative values result in an indefinite wait\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if a variable was updated on the host\&. X_NO_INIT if the SMA-X sharing was not initialized via \fBsmaxConnect()\fP\&. X_GROUP_INVALID if the table name to match is invalid\&. X_REL_PREMATURE if \fBsmaxReleaseWaits()\fP was called\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSubscribe()\fP +.PP +\fBsmaxWaitOnSubscribedVar()\fP +.PP +\fBsmaxWaitOnSubscribed()\fP +.PP +\fBsmaxWaitOnAnySubscribed()\fP +.PP +\fBsmaxReleaseWaits()\fP +.RE +.PP + +.SS "int smaxWaitOnSubscribedVar (const char * matchKey, char ** changedTable, int timeout)" +Waits for a specific pushed variable from any group/table\&. There must be an active subscription that includes the specified variable in one or more groups/tables, or else the call will block indefinitely\&. +.PP +\fBParameters\fP +.RS 4 +\fImatchKey\fP Variable name to wait on\&. +.br +\fIchangedTable\fP Pointer to the string that holds the name of the table which unblocked the wait or which is set to NULL\&. The lease of the buffer is for the call only\&. The caller should copy its content if persistent storage is required\&. +.br +\fItimeout\fP (s) Timeout value\&. 0 or negative values result in an indefinite wait\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if the variable was updated on some host (or owner)\&. X_NO_INIT if the SMA-X sharing was not initialized via \fBsmaxConnect()\fP\&. X_NAME_INVALID if the 'key' argument is NULL\&. X_REL_PREMATURE if \fBsmaxReleaseWaits()\fP was called\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSubscribe()\fP +.PP +\fBsmaxWaitOnSubscribedGroup()\fP +.PP +\fBsmaxWaitOnSubscribed()\fP +.PP +\fBsmaxWaitOnAnySubscribed()\fP +.PP +\fBsmaxReleaseWaits()\fP +.RE +.PP + +.SS "int smaxWaitQueueComplete (int timeoutMillis)" +Waits until all queued pull requests have been retrieved from the database, or until the specified timeout it reached\&. +.PP +\fBParameters\fP +.RS 4 +\fItimeoutMillis\fP An optional timeout in milliseconds\&. When set to a positive value The call will be guaranteed to return in the specified interval, whether or not the pipelined reads all succeeded\&. The return value can be used to check for errors or if the call timed out before all data were collected\&. If X_TIMEDOUT is returned, smax_end_bulk_pulls() may be called again to allow more time for the queued read operations to complete\&. 0 or negative timeout values will cause the call to wait indefinitely until reads are complete\&. +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if all reads have completed successfully, or the first read error that was enountered (e\&.g\&. RM_INVALID_KEY), or: X_TIMEDOUT if the call timed out while still awaiting data for the queued read requests\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmaxSync()\fP +.RE +.PP + +.PP +References \fBXSyncPoint::isComplete\fP, \fBXSyncPoint::lock\fP, \fBsmaxSync()\fP, and \fBXSyncPoint::status\fP\&. +.SS "int x2smaxField (XField * f)" +Converts a standard xchange field (with a native value storage) to an SMA-X field with serialized string value storage\&. +.PP +\fBParameters\fP +.RS 4 +\fIf\fP Pointer to field to convert +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_NULL if the input field or the serialized value is NULL\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmax2xField()\fP +.PP +\fBx2smaxStruct()\fP +.RE +.PP + +.PP +References \fBsmaxValuesToString()\fP, and \fBx2smaxStruct()\fP\&. +.SS "int x2smaxStruct (XStructure * s)" +Converts a standard xchange structure (with a native value storage) to an SMA-X structure with serialized string value storage\&. +.PP +\fBParameters\fP +.RS 4 +\fIs\fP Pointer to structure to convert +.RE +.PP +\fBReturns\fP +.RS 4 +X_SUCCESS (0) if successful, or X_STRUCT_INVALID if the structure is NULL, or had a NULL substructure\&. X_NULL if there was a field that could not be converted\&. +.RE +.PP +\fBSee also\fP +.RS 4 +\fBsmax2xStruct()\fP +.PP +\fBx2smaxField()\fP +.RE +.PP + +.PP +References \fBx2smaxField()\fP\&. +.SH "Author" +.PP +Generated automatically by Doxygen for smax-clib from the source code\&. diff --git a/apidoc/smax.tag b/apidoc/smax.tag new file mode 100644 index 0000000..9f9deec --- /dev/null +++ b/apidoc/smax.tag @@ -0,0 +1,2576 @@ + + + + smax-private.h + include/ + smax-private_8h.html + smax.h + + #define + __XCHANGE_INTERNAL_API__ + smax-private_8h.html + ac36bd75f87a1614fb477a0fbcd5df1f3 + + + + #define + RELEASEID + smax-private_8h.html + acb5965a4e56d8d90d76002bef3207ef9 + + + + + smax.h + include/ + smax_8h.html + XCoordinateAxis + XCoordinateSystem + XMessage + XMeta + XSyncPoint + + #define + META_COORDS + smax_8h.html + a6306140d9f65104bc6e0bfd63cbbc2f1 + + + + #define + META_DESCRIPTION + smax_8h.html + a3cd80ac3dbca64268a52d6bc8b273d82 + + + + #define + META_UNIT + smax_8h.html + aa1f2f2081a2949053cf74cd4ad47a8d2 + + + + #define + SMAX_DEFAULT_HOSTNAME + smax_8h.html + a0fe198db49d87d696072c261e49f7cce + + + + #define + SMAX_DEFAULT_MAX_QUEUED + smax_8h.html + aeb7304db99c63c3f0a10fca90e74abe4 + + + + #define + SMAX_DEFAULT_PIPELINE_ENABLED + smax_8h.html + aac2af1cdc522f5e3acc75edf7d41b267 + + + + #define + SMAX_DIMS + smax_8h.html + a59b5959fb0859d4dbe98408f2cc2f1d0 + + + + #define + SMAX_MSG_DEBUG + smax_8h.html + a8b3859624653c39bebe617c91567ad0d + + + + #define + SMAX_MSG_DETAIL + smax_8h.html + a06ee6433a1353c48c2c8ce5e8fd6631c + + + + #define + SMAX_MSG_ERROR + smax_8h.html + aeae00b97b43f8563939cd9ebcfdc4c62 + + + + #define + SMAX_MSG_INFO + smax_8h.html + a539edc8fa4545dbe7c388e8f0644f6c0 + + + + #define + SMAX_MSG_PROGRESS + smax_8h.html + a52b656c8731bc8ef9ef83d5307fd157e + + + + #define + SMAX_MSG_STATUS + smax_8h.html + a3168f34d2cd8afae9e9f9848ee684597 + + + + #define + SMAX_MSG_WARNING + smax_8h.html + a007762d6503940a6e287efab02083276 + + + + #define + SMAX_ORIGIN_LENGTH + smax_8h.html + a012a406ddc842479b2aefaa987e6c591 + + + + #define + SMAX_ORIGINS + smax_8h.html + a30235420adcb90ff2d2a0f6085a23427 + + + + #define + SMAX_PIPE_READ_TIMEOUT_MILLIS + smax_8h.html + a38eb97e64eaf65a5273fa6d6ff765a93 + + + + #define + SMAX_READS + smax_8h.html + ab986e2d3951e64cb3300a62c1f010551 + + + + #define + SMAX_RECONNECT_RETRY_SECONDS + smax_8h.html + a3e9baa458ae59eb26923d6ce863bf700 + + + + #define + SMAX_RESTORE_QUEUE_ON_RECONNECT + smax_8h.html + a2f111386ac4b76cd858de99478720b29 + + + + #define + SMAX_SCRIPTS + smax_8h.html + a23dedcaf9704eed433cf3920af5e5e1c + + + + #define + SMAX_TIMESTAMPS + smax_8h.html + ab5e13a0e5a3b57b087a2c875a01317b4 + + + + #define + SMAX_TYPES + smax_8h.html + a6933f3dab1f1de96cca777d65cdd5c40 + + + + #define + SMAX_UPDATES + smax_8h.html + a341a9de00cacd431dcd8ac8622b0bf7d + + + + #define + SMAX_UPDATES_LENGTH + smax_8h.html + ac59ccff9171d5b4e9545fd1ceef027b8 + + + + #define + SMAX_UPDATES_ROOT + smax_8h.html + abfefd74fb72fc51e4577d1fa5fa832f4 + + + + #define + SMAX_WRITES + smax_8h.html + af6088c6c91a1f0089000288f0214f67c + + + + #define + X_META_INIT + smax_8h.html + a793fead1eb30470e219192befc88b3c9 + + + + int + smax2xField + smax_8h.html + abfe751f22aa718133911ffdee848f64a + (XField *f) + + + int + smax2xStruct + smax_8h.html + a50fef3b0daf40f7de6f52b05abd2963c + (XStructure *s) + + + int + smaxAddConnectHook + smax_8h.html + ad63c425cc3affdf8bc803c7ff8dd6e30 + (void(*setupCall)(void)) + + + int + smaxAddDefaultMessageProcessor + smax_8h.html + aa3e777f85e81ffb9b02dc8cc3d124a94 + (const char *host, const char *prog, const char *type) + + + int + smaxAddDisconnectHook + smax_8h.html + a65ae161b28cfe4369709fae1d3ea678c + (void(*cleanupCall)(void)) + + + int + smaxAddMessageProcessor + smax_8h.html + abaa2573fb8e85e8359c8853647c38f2f + (const char *host, const char *prog, const char *type, void(*f)(XMessage *)) + + + int + smaxAddSubscriber + smax_8h.html + a1714cac6dfa55917edecd0028e6da64c + (const char *stem, RedisSubscriberCall f) + + + int + smaxConnect + smax_8h.html + a146fb2ed8512919dc91ecad6d08c74d1 + () + + + int + smaxConnectTo + smax_8h.html + ad960c22b119ff2493a319945a9dd55a5 + (const char *server) + + + XField * + smaxCreate1DField + smax_8h.html + afba357d35d2a1f13d0cf06f5ff708a99 + (const char *name, XType type, int size, const void *value) + + + XField * + smaxCreateBooleanField + smax_8h.html + a13e357c3f20c0799fba6bc6c2a16c520 + (const char *name, boolean value) + + + XCoordinateSystem * + smaxCreateCoordinateSystem + smax_8h.html + a1d977e7e9eb45f9ce6cc338fdde9bd8f + (int nAxis) + + + XField * + smaxCreateDoubleField + smax_8h.html + afa9c9ec0f47236c0c560eee724b809d6 + (const char *name, double value) + + + XField * + smaxCreateField + smax_8h.html + a9871356984c4794a9f9caa3870dc6794 + (const char *name, XType type, int ndim, const int *sizes, const void *value) + + + XField * + smaxCreateIntField + smax_8h.html + afcb9ce5f154eef8eccdb0930ec4d613d + (const char *name, int value) + + + XField * + smaxCreateLongField + smax_8h.html + a23b55eae1ce68356073ea5b191f915e5 + (const char *name, long long value) + + + XMeta * + smaxCreateMeta + smax_8h.html + a48decaf10195b2f21fa77d8ea9b94fff + () + + + XField * + smaxCreateScalarField + smax_8h.html + a61a3760159e6867cdb55b5995435633c + (const char *name, XType type, const void *value) + + + XField * + smaxCreateStringField + smax_8h.html + aa5c7661e29f4f1ba62f457c7138f2654 + (const char *name, const char *value) + + + XSyncPoint * + smaxCreateSyncPoint + smax_8h.html + a30e2e1eb462ed2274a55016830b9abc1 + () + + + int + smaxDeletePattern + smax_8h.html + a6c116311d61874554f98332831ad872b + (const char *pattern) + + + void + smaxDestroyCoordinateSystem + smax_8h.html + a92cf6cd3b3f123e21a1cee437f87126d + (XCoordinateSystem *coords) + + + void + smaxDestroySyncPoint + smax_8h.html + a97ace8424abf924b8ae0397ae83177f2 + (XSyncPoint *sync) + + + int + smaxDisconnect + smax_8h.html + a9d1e6ffa837d3582a8165e326cc44bea + () + + + int + smaxError + smax_8h.html + aefcb16af3690ffe9c77224af6b394869 + (const char *func, int errorCode) + + + const char * + smaxErrorDescription + smax_8h.html + a51856e0dc0261f8e44c8635d31d6193c + (int code) + + + int + smaxGetArrayField + smax_8h.html + a10525c664231e85f3cd9a592915b8919 + (const XStructure *s, const char *name, void *dst, XType type, int count) + + + boolean + smaxGetBooleanField + smax_8h.html + a555c133ddd7aee3cf481f9e5e15e3d43 + (const XStructure *s, const char *name, boolean defaultValue) + + + XCoordinateAxis * + smaxGetCoordinateAxis + smax_8h.html + a349dc6fe14a2031d679e29804d82d570 + (const char *id, int n) + + + XCoordinateSystem * + smaxGetCoordinateSystem + smax_8h.html + a2920bd71f9d340422e0b1b0db4bb3201 + (const char *table, const char *key) + + + char * + smaxGetDescription + smax_8h.html + ad7ef601ffd5fbcae7b2c05be6f6bc302 + (const char *table, const char *key) + + + double + smaxGetDoubleField + smax_8h.html + ab7c45d4512c22c24153763aa9e227b68 + (const XStructure *s, const char *name, double defaultValue) + + + char * + smaxGetHostName + smax_8h.html + ac704fea3e664905af780d2566e3c74b6 + () + + + char ** + smaxGetKeys + smax_8h.html + a2544d1fa602e812004e1d68500024ae0 + (const char *table, int *n) + + + int + smaxGetLazyCached + smax_8h.html + a42c08f13c70400dc1225d4097342ded0 + (const char *table, const char *key, XType type, int count, void *value, XMeta *meta) + + + int + smaxGetLazyUpdateCount + smax_8h.html + aeca4aa02259278b240e4131f7edea816 + (const char *table, const char *key) + + + long long + smaxGetLongField + smax_8h.html + a8035211bd1fe17551a1517560b2547c4 + (const XStructure *s, const char *name, long long defaultValue) + + + int + smaxGetMetaCount + smax_8h.html + ac6d47a508669e4ee215cb72c5366fc52 + (const XMeta *m) + + + char * + smaxGetProgramID + smax_8h.html + abc07a7599e0bac1be15bbcb6b63d4710 + () + + + char * + smaxGetRawField + smax_8h.html + ada517cdb7737bb38695e2a343123583b + (const XStructure *s, const char *name, char *defaultValue) + + + Redis * + smaxGetRedis + smax_8h.html + a533fbe770158afe876a3dafa78ba2195 + () + + + char * + smaxGetScriptSHA1 + smax_8h.html + a8ef420555c1ddbbcd9f4213f65b4ca66 + (const char *scriptName, int *status) + + + int + smaxGetServerTime + smax_8h.html + ae6941b762acbd37c60b012d4157681a8 + (struct timespec *t) + + + double + smaxGetTime + smax_8h.html + a2a71d93de952060be0154dd5f0d78496 + (const char *timestamp) + + + char * + smaxGetUnits + smax_8h.html + aa27e3adeb67f2328a162c80bad433f02 + (const char *table, const char *key) + + + int + smaxIsConnected + smax_8h.html + a95cbb68e3eb751219ab3363c93a4840b + () + + + boolean + smaxIsPipelined + smax_8h.html + af6f57a699b784fc67534cff0abd9573b + () + + + boolean + smaxIsResilient + smax_8h.html + a5f5e00f0fd063ac8e36827c852131358 + () + + + boolean + smaxIsVerbose + smax_8h.html + a980232c82ed7ebf5425c60db65f828c0 + () + + + int + smaxKeyCount + smax_8h.html + a7030106bbe70220c97b1e9e3a4633ff4 + (const char *table) + + + int + smaxLazyCache + smax_8h.html + a18027e41c40722011815bc878857e3d0 + (const char *table, const char *key, XType type) + + + int + smaxLazyEnd + smax_8h.html + a167a60b494fa9ec5b046f9da796f18b5 + (const char *table, const char *key) + + + int + smaxLazyFlush + smax_8h.html + af3d0cff3f8a6ab745907f4544981fdd1 + () + + + int + smaxLazyPull + smax_8h.html + ab50222d7bbaa985fd6d004d67b0269ce + (const char *table, const char *key, XType type, int count, void *value, XMeta *meta) + + + int + smaxLazyPullChars + smax_8h.html + a45d5c86c16869e5208b9c5cf688adc53 + (const char *table, const char *key, char *buf, int n) + + + double + smaxLazyPullDouble + smax_8h.html + a31ed83292a29d69e1c9635b21aae7561 + (const char *table, const char *key) + + + double + smaxLazyPullDoubleDefault + smax_8h.html + ac823bc3c1ee1bdbc4c330366fc246c8e + (const char *table, const char *key, double defaultValue) + + + long long + smaxLazyPullLong + smax_8h.html + a03e3bb5c838dc621f8c0ba5fb6fe5f87 + (const char *table, const char *key, long long defaultValue) + + + char * + smaxLazyPullString + smax_8h.html + a38d33bcbf9f2f73adbaf040996279859 + (const char *table, const char *key) + + + int + smaxLazyPullStruct + smax_8h.html + af96429709d1b029a8db74cb7407f9ffb + (const char *id, XStructure *s) + + + int + smaxParseTime + smax_8h.html + a2c3c82ba5e7844e9f1b70fb4d51716ef + (const char *timestamp, time_t *secs, long *nanosecs) + + + int + smaxPull + smax_8h.html + afb7eec789669c3d3f416857d3615ace6 + (const char *table, const char *key, XType type, int count, void *value, XMeta *meta) + + + double + smaxPullDouble + smax_8h.html + aa143c2385f210cdd772f014939e1411e + (const char *table, const char *key) + + + double + smaxPullDoubleDefault + smax_8h.html + a1d30cb3f0a48b567657975a104a1088f + (const char *table, const char *key, double defaultValue) + + + double * + smaxPullDoubles + smax_8h.html + a6e5df36b7eee3944b1ef07edb7f9647d + (const char *table, const char *key, XMeta *meta, int *n) + + + int + smaxPullInt + smax_8h.html + a42685e249ca24359b0f3f2a04a99b16b + (const char *table, const char *key, int defaultValue) + + + int * + smaxPullInts + smax_8h.html + a8cdf0e4d01eaa160b8c96593ce32f4ff + (const char *table, const char *key, XMeta *meta, int *n) + + + long long + smaxPullLong + smax_8h.html + aebedc01880d4253e74b8bde565de00d5 + (const char *table, const char *key, long long defaultValue) + + + long long * + smaxPullLongs + smax_8h.html + a843fa579fa26190335aeebb87be63203 + (const char *table, const char *key, XMeta *meta, int *n) + + + char * + smaxPullMeta + smax_8h.html + a0d29e7a895c1d5fdc6258ff7426b3521 + (const char *meta, const char *table, const char *key, int *status) + + + char * + smaxPullRaw + smax_8h.html + a0de71a90fdf235a8aee084543591244f + (const char *table, const char *key, XMeta *meta, int *status) + + + char * + smaxPullString + smax_8h.html + a41bdf6bb7bcb3f0d3cb1c0657f8da1c5 + (const char *table, const char *key) + + + char ** + smaxPullStrings + smax_8h.html + abc833f0d89e672507e0baeb146e8776b + (const char *table, const char *key, XMeta *meta, int *n) + + + XStructure * + smaxPullStruct + smax_8h.html + ae6d8bf54e6ca203ea25a066d6e439ae5 + (const char *name, XMeta *meta, int *status) + + + double + smaxPullTime + smax_8h.html + a6deedf594f19417bfa11b8f2cef360c4 + (const char *table, const char *key) + + + XType + smaxPullTypeDimension + smax_8h.html + ab989b724600841b16125977bcb44ffcc + (const char *table, const char *key, int *ndim, int *sizes) + + + int + smaxPushMeta + smax_8h.html + aaf4c866eb1cb30dfd70e04604f1aa6cf + (const char *meta, const char *table, const char *key, const char *value) + + + int + smaxQueue + smax_8h.html + a2c71427a215e2253d93de24788db338d + (const char *table, const char *key, XType type, int count, void *value, XMeta *meta) + + + int + smaxQueueCallback + smax_8h.html + a06781e13ee30b0530ba3ed2e4436b449 + (void(*f)(void *), void *arg) + + + int + smaxReconnect + smax_8h.html + aafc75a2e8b8858b8ff0f16e0e73dbd03 + () + + + int + smaxReleaseWaits + smax_8h.html + a14bc33c30d27be9e2954ae7831099f1c + () + + + int + smaxRemoveConnectHook + smax_8h.html + a4708c3c699781abec237045c48719f3d + (void(*setupCall)(void)) + + + int + smaxRemoveDisconnectHook + smax_8h.html + a70cdc3f1bf6b97248b5b8ba6df4dc044 + (void(*cleanupCall)(void)) + + + int + smaxRemoveMessageProcessor + smax_8h.html + a1550f0f7aed841d5576d47ec7e62e0c4 + (int id) + + + int + smaxRemoveSubscribers + smax_8h.html + a77d04f4fbb447f169d40b2a24fa7cf71 + (RedisSubscriberCall f) + + + void + smaxResetMeta + smax_8h.html + a7ea3483859bf8f7764143b8590af067e + (XMeta *m) + + + int + smaxSendDebug + smax_8h.html + a6c8e73f27c445dedd5ba4ac5b399f8d1 + (const char *msg) + + + int + smaxSendDetail + smax_8h.html + a2a0607da9db140f4227524da37b3bf51 + (const char *msg) + + + int + smaxSendError + smax_8h.html + a7d936da43078b9be469a97a6a4bb82a8 + (const char *msg) + + + int + smaxSendInfo + smax_8h.html + a6056608a81e52d070dcc0f3ee96579b5 + (const char *msg) + + + int + smaxSendProgress + smax_8h.html + a0f32699c2148f3b09a48e84b3fa4d036 + (double fraction, const char *msg) + + + int + smaxSendStatus + smax_8h.html + a3739383ee6770337b3bb023cfe0cc64c + (const char *msg) + + + int + smaxSendWarning + smax_8h.html + a740f4a171334a6aa5d4736c15fc327e4 + (const char *msg) + + + int + smaxSetAuth + smax_8h.html + a097b12d3bbb43175084b0b0a2f55339c + (const char *username, const char *password) + + + int + smaxSetCoordinateAxis + smax_8h.html + a5d59620a1646428f41b040d1a0a91554 + (const char *id, int n, const XCoordinateAxis *axis) + + + int + smaxSetCoordinateSystem + smax_8h.html + a04c3b8ea7ff6b8117d2dba9bf9edd52f + (const char *table, const char *key, const XCoordinateSystem *coords) + + + int + smaxSetDB + smax_8h.html + a79fba7411b5afa132457a6828ff5ed9f + (int idx) + + + int + smaxSetDescription + smax_8h.html + adcc70ef29ab29f28068ac57e40497b85 + (const char *table, const char *key, const char *description) + + + void + smaxSetHostName + smax_8h.html + a886e2ed23987201a9808f1c99806b44a + (const char *name) + + + int + smaxSetMaxPendingPulls + smax_8h.html + a7b7ff182bf54594d796d52e7d6a1a41d + (int n) + + + void + smaxSetMessageSenderID + smax_8h.html + af3e8295bb941f68cf3177c79cd5fb4d3 + (const char *id) + + + void + smaxSetOrigin + smax_8h.html + a9802443ba0d569c3614f5dcf8b0cfc4b + (XMeta *m, const char *origin) + + + int + smaxSetPipelineConsumer + smax_8h.html + a542b4c264a49b61a6cd25881290df1d1 + (void(*f)(RESP *)) + + + int + smaxSetPipelined + smax_8h.html + a8d7a3f57360d8e505baa78e445a53875 + (boolean isEnabled) + + + void + smaxSetResilient + smax_8h.html + a469095a9a74a8ce5d6bbae347d7194e5 + (boolean value) + + + void + smaxSetResilientExit + smax_8h.html + ae638a5b4c82119eea5ef7a0ba2cd40c1 + (boolean value) + + + int + smaxSetServer + smax_8h.html + a78cf94f007034f63b609cbe72b8047b0 + (const char *host, int port) + + + int + smaxSetTcpBuf + smax_8h.html + ac42ee8e8128aac0695c68660f04fd196 + (int size) + + + int + smaxSetUnits + smax_8h.html + a23e6627339f6bf58e87150aa9ff0c964 + (const char *table, const char *key, const char *unit) + + + void + smaxSetVerbose + smax_8h.html + ac43709380b9ad92133a22ae0d52d107c + (boolean value) + + + int + smaxShare + smax_8h.html + aee07f085e12283ad96f42c4d77430880 + (const char *table, const char *key, const void *value, XType type, int count) + + + int + smaxShareArray + smax_8h.html + a403f2a3f6186c554cba80ff397ea6a9a + (const char *table, const char *key, const void *value, XType type, int ndim, const int *sizes) + + + int + smaxShareBoolean + smax_8h.html + a294640494c2d892dfb4944cd9da7729a + (const char *table, const char *key, boolean value) + + + int + smaxShareBooleans + smax_8h.html + ad4ddc1226e77667c74dd0c3e0cff56a0 + (const char *table, const char *key, const boolean *values, int n) + + + int + smaxShareBytes + smax_8h.html + a9274e66d69bf41bbe291bbadbb619acc + (const char *table, const char *key, const char *values, int n) + + + int + smaxShareDouble + smax_8h.html + acfbfd2b9a23305d75e45541c5177e42a + (const char *table, const char *key, double value) + + + int + smaxShareDoubles + smax_8h.html + a1195017071e3733c0ff9c9f6e704e593 + (const char *table, const char *key, const double *values, int n) + + + int + smaxShareField + smax_8h.html + a0da1227278e6bc105c7dbdba14fd884a + (const char *table, const XField *f) + + + int + smaxShareFloats + smax_8h.html + ace410207bfb5ba9211dc644f7dd2768d + (const char *table, const char *key, const float *values, int n) + + + int + smaxShareHex + smax_8h.html + a9efb328571eb7aac0cec75b55676c4e0 + (const char *table, const char *key, long long value) + + + int + smaxShareInt + smax_8h.html + adeb667a3e72acedee7d03eb246b8e1ae + (const char *table, const char *key, long long value) + + + int + smaxShareInts + smax_8h.html + acc2181d635e635e330f6e01b7643dadb + (const char *table, const char *key, const int *values, int n) + + + int + smaxShareLongs + smax_8h.html + a179730ae8cc7517c96b3e7efb81411fb + (const char *table, const char *key, const long long *values, int n) + + + int + smaxShareShorts + smax_8h.html + a007815fcac77e840c851a54f97d575ae + (const char *table, const char *key, const short *values, int n) + + + int + smaxShareString + smax_8h.html + a5c9657c01a9b8a324a9a1d318dd18e5b + (const char *table, const char *key, const char *sValue) + + + int + smaxShareStrings + smax_8h.html + a63c421116ca043f2d0899b83d8aa91f9 + (const char *table, const char *key, const char **sValues, int n) + + + int + smaxShareStruct + smax_8h.html + ab6a1590c953abc1c37fed841cd3a903a + (const char *id, const XStructure *s) + + + int + smaxStringToValues + smax_8h.html + af57aab7c00cf249480b8fda660dc0256 + (const char *str, void *value, XType type, int count, int *parsed) + + + char * + smaxStringType + smax_8h.html + a8d9d92ad8825d4adad4d6288a5681351 + (XType type) + + + int + smaxSubscribe + smax_8h.html + a53614ba57a594135c13b64a2d89eaa43 + (const char *table, const char *key) + + + int + smaxSync + smax_8h.html + a90a901b9e649c77d29379b8fc31cbefc + (XSyncPoint *sync, int timeoutMillis) + + + int + smaxTimestamp + smax_8h.html + ae56da599747b207813a710efc07dd47d + (char *buf) + + + int + smaxTimeToString + smax_8h.html + a49ca81e757e023205085a23c3aa7e3da + (const struct timespec *time, char *buf) + + + XType + smaxTypeForString + smax_8h.html + af6a70e896526629e2130009882a1bff8 + (const char *type) + + + int + smaxUnpackStrings + smax_8h.html + a5665cd4f5087ab7a07239c30bc561173 + (const char *data, int len, int count, char **dst) + + + int + smaxUnsubscribe + smax_8h.html + af3a5d7bc565ab7de0ac1dd8fafc93f14 + (const char *table, const char *key) + + + char * + smaxValuesToString + smax_8h.html + ae67f864946fbcd880e7b5c98b2f876c5 + (const void *value, XType type, int count, char *trybuf, int trylength) + + + int + smaxWaitOnAnySubscribed + smax_8h.html + a89db98657eab826392d6099d21fff14c + (char **changedTable, char **changedKey, int timeout) + + + int + smaxWaitOnSubscribed + smax_8h.html + a0e116b41cf8cfbca058dba8476b5d573 + (const char *table, const char *key, int timeout) + + + int + smaxWaitOnSubscribedGroup + smax_8h.html + af6cae99a805bf84e98390e0bea2470b7 + (const char *matchTable, char **changedKey, int timeout) + + + int + smaxWaitOnSubscribedVar + smax_8h.html + af54b8b5d2e79eda86b3349c3c138331c + (const char *matchKey, char **changedTable, int timeout) + + + int + smaxWaitQueueComplete + smax_8h.html + a065361085eed93188b7fd3ffe3a7eaf5 + (int timeoutMillis) + + + int + x2smaxField + smax_8h.html + a76bd110891905fe4bdae6628547c50d1 + (XField *f) + + + int + x2smaxStruct + smax_8h.html + a65cc6cdad09f861b968e2d492abed977 + (XStructure *s) + + + + smax-easy.c + src/ + smax-easy_8c.html + smax-private.h + + XField * + smaxCreate1DField + smax-easy_8c.html + afba357d35d2a1f13d0cf06f5ff708a99 + (const char *name, XType type, int size, const void *value) + + + XField * + smaxCreateBooleanField + smax-easy_8c.html + a13e357c3f20c0799fba6bc6c2a16c520 + (const char *name, boolean value) + + + XField * + smaxCreateDoubleField + smax-easy_8c.html + afa9c9ec0f47236c0c560eee724b809d6 + (const char *name, double value) + + + XField * + smaxCreateIntField + smax-easy_8c.html + afcb9ce5f154eef8eccdb0930ec4d613d + (const char *name, int value) + + + XField * + smaxCreateLongField + smax-easy_8c.html + a23b55eae1ce68356073ea5b191f915e5 + (const char *name, long long value) + + + XField * + smaxCreateScalarField + smax-easy_8c.html + a61a3760159e6867cdb55b5995435633c + (const char *name, XType type, const void *value) + + + XField * + smaxCreateStringField + smax-easy_8c.html + aa5c7661e29f4f1ba62f457c7138f2654 + (const char *name, const char *value) + + + int + smaxGetArrayField + smax-easy_8c.html + a10525c664231e85f3cd9a592915b8919 + (const XStructure *s, const char *name, void *dst, XType type, int count) + + + boolean + smaxGetBooleanField + smax-easy_8c.html + a555c133ddd7aee3cf481f9e5e15e3d43 + (const XStructure *s, const char *name, boolean defaultValue) + + + double + smaxGetDoubleField + smax-easy_8c.html + ab7c45d4512c22c24153763aa9e227b68 + (const XStructure *s, const char *name, double defaultValue) + + + long long + smaxGetLongField + smax-easy_8c.html + a8035211bd1fe17551a1517560b2547c4 + (const XStructure *s, const char *name, long long defaultValue) + + + char * + smaxGetRawField + smax-easy_8c.html + ada517cdb7737bb38695e2a343123583b + (const XStructure *s, const char *name, char *defaultValue) + + + double + smaxPullDouble + smax-easy_8c.html + aa143c2385f210cdd772f014939e1411e + (const char *table, const char *key) + + + double + smaxPullDoubleDefault + smax-easy_8c.html + a1d30cb3f0a48b567657975a104a1088f + (const char *table, const char *key, double defaultValue) + + + double * + smaxPullDoubles + smax-easy_8c.html + a6e5df36b7eee3944b1ef07edb7f9647d + (const char *table, const char *key, XMeta *meta, int *n) + + + int + smaxPullInt + smax-easy_8c.html + a42685e249ca24359b0f3f2a04a99b16b + (const char *table, const char *key, int defaultValue) + + + int * + smaxPullInts + smax-easy_8c.html + a8cdf0e4d01eaa160b8c96593ce32f4ff + (const char *table, const char *key, XMeta *meta, int *n) + + + long long + smaxPullLong + smax-easy_8c.html + aebedc01880d4253e74b8bde565de00d5 + (const char *table, const char *key, long long defaultValue) + + + long long * + smaxPullLongs + smax-easy_8c.html + a843fa579fa26190335aeebb87be63203 + (const char *table, const char *key, XMeta *meta, int *n) + + + char * + smaxPullRaw + smax-easy_8c.html + a0de71a90fdf235a8aee084543591244f + (const char *table, const char *key, XMeta *meta, int *status) + + + char * + smaxPullString + smax-easy_8c.html + a41bdf6bb7bcb3f0d3cb1c0657f8da1c5 + (const char *table, const char *key) + + + char ** + smaxPullStrings + smax-easy_8c.html + abc833f0d89e672507e0baeb146e8776b + (const char *table, const char *key, XMeta *meta, int *n) + + + XStructure * + smaxPullStruct + smax-easy_8c.html + a30a2212f19ab2cbf60ea348110475948 + (const char *id, XMeta *meta, int *status) + + + int + smaxShareBoolean + smax-easy_8c.html + a294640494c2d892dfb4944cd9da7729a + (const char *table, const char *key, boolean value) + + + int + smaxShareBooleans + smax-easy_8c.html + ad4ddc1226e77667c74dd0c3e0cff56a0 + (const char *table, const char *key, const boolean *values, int n) + + + int + smaxShareBytes + smax-easy_8c.html + a9274e66d69bf41bbe291bbadbb619acc + (const char *table, const char *key, const char *values, int n) + + + int + smaxShareDouble + smax-easy_8c.html + acfbfd2b9a23305d75e45541c5177e42a + (const char *table, const char *key, double value) + + + int + smaxShareDoubles + smax-easy_8c.html + a1195017071e3733c0ff9c9f6e704e593 + (const char *table, const char *key, const double *values, int n) + + + int + smaxShareFloats + smax-easy_8c.html + ace410207bfb5ba9211dc644f7dd2768d + (const char *table, const char *key, const float *values, int n) + + + int + smaxShareHex + smax-easy_8c.html + a9efb328571eb7aac0cec75b55676c4e0 + (const char *table, const char *key, long long value) + + + int + smaxShareInt + smax-easy_8c.html + adeb667a3e72acedee7d03eb246b8e1ae + (const char *table, const char *key, long long value) + + + int + smaxShareInts + smax-easy_8c.html + acc2181d635e635e330f6e01b7643dadb + (const char *table, const char *key, const int *values, int n) + + + int + smaxShareLongs + smax-easy_8c.html + a179730ae8cc7517c96b3e7efb81411fb + (const char *table, const char *key, const long long *values, int n) + + + int + smaxShareShorts + smax-easy_8c.html + a007815fcac77e840c851a54f97d575ae + (const char *table, const char *key, const short *values, int n) + + + int + smaxShareString + smax-easy_8c.html + a5c9657c01a9b8a324a9a1d318dd18e5b + (const char *table, const char *key, const char *sValue) + + + int + smaxShareStrings + smax-easy_8c.html + a63c421116ca043f2d0899b83d8aa91f9 + (const char *table, const char *key, const char **sValues, int n) + + + int + smaxWaitOnSubscribed + smax-easy_8c.html + a0e116b41cf8cfbca058dba8476b5d573 + (const char *table, const char *key, int timeout) + + + int + smaxWaitOnSubscribedGroup + smax-easy_8c.html + af6cae99a805bf84e98390e0bea2470b7 + (const char *matchTable, char **changedKey, int timeout) + + + int + smaxWaitOnSubscribedVar + smax-easy_8c.html + af54b8b5d2e79eda86b3349c3c138331c + (const char *matchKey, char **changedTable, int timeout) + + + + smax-lazy.c + src/ + smax-lazy_8c.html + smax-private.h + + int + smaxGetLazyCached + smax-lazy_8c.html + a42c08f13c70400dc1225d4097342ded0 + (const char *table, const char *key, XType type, int count, void *value, XMeta *meta) + + + int + smaxGetLazyUpdateCount + smax-lazy_8c.html + aeca4aa02259278b240e4131f7edea816 + (const char *table, const char *key) + + + int + smaxLazyCache + smax-lazy_8c.html + a18027e41c40722011815bc878857e3d0 + (const char *table, const char *key, XType type) + + + int + smaxLazyEnd + smax-lazy_8c.html + a167a60b494fa9ec5b046f9da796f18b5 + (const char *table, const char *key) + + + int + smaxLazyFlush + smax-lazy_8c.html + af3d0cff3f8a6ab745907f4544981fdd1 + () + + + int + smaxLazyPull + smax-lazy_8c.html + ab50222d7bbaa985fd6d004d67b0269ce + (const char *table, const char *key, XType type, int count, void *value, XMeta *meta) + + + int + smaxLazyPullChars + smax-lazy_8c.html + a45d5c86c16869e5208b9c5cf688adc53 + (const char *table, const char *key, char *buf, int n) + + + double + smaxLazyPullDouble + smax-lazy_8c.html + a31ed83292a29d69e1c9635b21aae7561 + (const char *table, const char *key) + + + double + smaxLazyPullDoubleDefault + smax-lazy_8c.html + ac823bc3c1ee1bdbc4c330366fc246c8e + (const char *table, const char *key, double defaultValue) + + + long long + smaxLazyPullLong + smax-lazy_8c.html + a03e3bb5c838dc621f8c0ba5fb6fe5f87 + (const char *table, const char *key, long long defaultValue) + + + char * + smaxLazyPullString + smax-lazy_8c.html + a38d33bcbf9f2f73adbaf040996279859 + (const char *table, const char *key) + + + int + smaxLazyPullStruct + smax-lazy_8c.html + af96429709d1b029a8db74cb7407f9ffb + (const char *id, XStructure *s) + + + + smax-messages.c + src/ + smax-messages_8c.html + smax-private.h + + #define + MESSAGES_ID + smax-messages_8c.html + a7b2e3f4ba6d955bd23ae56f2a2d9a3e3 + + + + #define + MESSAGES_PREFIX + smax-messages_8c.html + a309d33601440402f7f3fb5175864b62b + + + + int + smaxAddDefaultMessageProcessor + smax-messages_8c.html + aa3e777f85e81ffb9b02dc8cc3d124a94 + (const char *host, const char *prog, const char *type) + + + int + smaxAddMessageProcessor + smax-messages_8c.html + abaa2573fb8e85e8359c8853647c38f2f + (const char *host, const char *prog, const char *type, void(*f)(XMessage *)) + + + int + smaxRemoveMessageProcessor + smax-messages_8c.html + a1550f0f7aed841d5576d47ec7e62e0c4 + (int id) + + + int + smaxSendDebug + smax-messages_8c.html + a6c8e73f27c445dedd5ba4ac5b399f8d1 + (const char *msg) + + + int + smaxSendDetail + smax-messages_8c.html + a2a0607da9db140f4227524da37b3bf51 + (const char *msg) + + + int + smaxSendError + smax-messages_8c.html + a7d936da43078b9be469a97a6a4bb82a8 + (const char *msg) + + + int + smaxSendInfo + smax-messages_8c.html + a6056608a81e52d070dcc0f3ee96579b5 + (const char *msg) + + + int + smaxSendProgress + smax-messages_8c.html + a0f32699c2148f3b09a48e84b3fa4d036 + (double fraction, const char *msg) + + + int + smaxSendStatus + smax-messages_8c.html + a3739383ee6770337b3bb023cfe0cc64c + (const char *msg) + + + int + smaxSendWarning + smax-messages_8c.html + a740f4a171334a6aa5d4736c15fc327e4 + (const char *msg) + + + void + smaxSetMessageSenderID + smax-messages_8c.html + af3e8295bb941f68cf3177c79cd5fb4d3 + (const char *id) + + + + smax-meta.c + src/ + smax-meta_8c.html + smax-private.h + + XCoordinateSystem * + smaxCreateCoordinateSystem + smax-meta_8c.html + a1d977e7e9eb45f9ce6cc338fdde9bd8f + (int nAxis) + + + void + smaxDestroyCoordinateSystem + smax-meta_8c.html + a92cf6cd3b3f123e21a1cee437f87126d + (XCoordinateSystem *coords) + + + XCoordinateAxis * + smaxGetCoordinateAxis + smax-meta_8c.html + a349dc6fe14a2031d679e29804d82d570 + (const char *id, int n) + + + XCoordinateSystem * + smaxGetCoordinateSystem + smax-meta_8c.html + a2920bd71f9d340422e0b1b0db4bb3201 + (const char *table, const char *key) + + + char * + smaxGetDescription + smax-meta_8c.html + ad7ef601ffd5fbcae7b2c05be6f6bc302 + (const char *table, const char *key) + + + char * + smaxGetUnits + smax-meta_8c.html + aa27e3adeb67f2328a162c80bad433f02 + (const char *table, const char *key) + + + char * + smaxPullMeta + smax-meta_8c.html + a0d29e7a895c1d5fdc6258ff7426b3521 + (const char *meta, const char *table, const char *key, int *status) + + + double + smaxPullTime + smax-meta_8c.html + a6deedf594f19417bfa11b8f2cef360c4 + (const char *table, const char *key) + + + XType + smaxPullTypeDimension + smax-meta_8c.html + ab989b724600841b16125977bcb44ffcc + (const char *table, const char *key, int *ndim, int *sizes) + + + int + smaxPushMeta + smax-meta_8c.html + aaf4c866eb1cb30dfd70e04604f1aa6cf + (const char *meta, const char *table, const char *key, const char *value) + + + int + smaxSetCoordinateAxis + smax-meta_8c.html + a5d59620a1646428f41b040d1a0a91554 + (const char *id, int n, const XCoordinateAxis *axis) + + + int + smaxSetCoordinateSystem + smax-meta_8c.html + a04c3b8ea7ff6b8117d2dba9bf9edd52f + (const char *table, const char *key, const XCoordinateSystem *coords) + + + int + smaxSetDescription + smax-meta_8c.html + adcc70ef29ab29f28068ac57e40497b85 + (const char *table, const char *key, const char *description) + + + int + smaxSetUnits + smax-meta_8c.html + a23e6627339f6bf58e87150aa9ff0c964 + (const char *table, const char *key, const char *unit) + + + + smax-queue.c + src/ + smax-queue_8c.html + smax-private.h + + XSyncPoint * + smaxCreateSyncPoint + smax-queue_8c.html + a30e2e1eb462ed2274a55016830b9abc1 + () + + + void + smaxDestroySyncPoint + smax-queue_8c.html + a012860edbebf45f24b1b08c02a37847b + (XSyncPoint *s) + + + int + smaxQueue + smax-queue_8c.html + a2c71427a215e2253d93de24788db338d + (const char *table, const char *key, XType type, int count, void *value, XMeta *meta) + + + int + smaxQueueCallback + smax-queue_8c.html + a06781e13ee30b0530ba3ed2e4436b449 + (void(*f)(void *), void *arg) + + + int + smaxSetMaxPendingPulls + smax-queue_8c.html + a7b7ff182bf54594d796d52e7d6a1a41d + (int n) + + + int + smaxSync + smax-queue_8c.html + a90a901b9e649c77d29379b8fc31cbefc + (XSyncPoint *sync, int timeoutMillis) + + + int + smaxWaitQueueComplete + smax-queue_8c.html + a065361085eed93188b7fd3ffe3a7eaf5 + (int timeoutMillis) + + + + smax-resilient.c + src/ + smax-resilient_8c.html + smax-private.h + + boolean + smaxIsResilient + smax-resilient_8c.html + a5f5e00f0fd063ac8e36827c852131358 + () + + + void + smaxSetResilient + smax-resilient_8c.html + a469095a9a74a8ce5d6bbae347d7194e5 + (boolean value) + + + void + smaxSetResilientExit + smax-resilient_8c.html + ae638a5b4c82119eea5ef7a0ba2cd40c1 + (boolean value) + + + + smax-util.c + src/ + smax-util_8c.html + smax-private.h + + int + smax2xField + smax-util_8c.html + abfe751f22aa718133911ffdee848f64a + (XField *f) + + + int + smax2xStruct + smax-util_8c.html + a50fef3b0daf40f7de6f52b05abd2963c + (XStructure *s) + + + XField * + smaxCreateField + smax-util_8c.html + a9871356984c4794a9f9caa3870dc6794 + (const char *name, XType type, int ndim, const int *sizes, const void *value) + + + XMeta * + smaxCreateMeta + smax-util_8c.html + a48decaf10195b2f21fa77d8ea9b94fff + () + + + int + smaxDeletePattern + smax-util_8c.html + a6c116311d61874554f98332831ad872b + (const char *pattern) + + + int + smaxError + smax-util_8c.html + aefcb16af3690ffe9c77224af6b394869 + (const char *func, int errorCode) + + + const char * + smaxErrorDescription + smax-util_8c.html + a51856e0dc0261f8e44c8635d31d6193c + (int code) + + + int + smaxGetMetaCount + smax-util_8c.html + ac6d47a508669e4ee215cb72c5366fc52 + (const XMeta *m) + + + char * + smaxGetScriptSHA1 + smax-util_8c.html + a8ef420555c1ddbbcd9f4213f65b4ca66 + (const char *scriptName, int *status) + + + int + smaxGetServerTime + smax-util_8c.html + ae6941b762acbd37c60b012d4157681a8 + (struct timespec *t) + + + double + smaxGetTime + smax-util_8c.html + a2a71d93de952060be0154dd5f0d78496 + (const char *timestamp) + + + int + smaxParseTime + smax-util_8c.html + a2c3c82ba5e7844e9f1b70fb4d51716ef + (const char *timestamp, time_t *secs, long *nanosecs) + + + void + smaxResetMeta + smax-util_8c.html + a7ea3483859bf8f7764143b8590af067e + (XMeta *m) + + + int + smaxScriptError + smax-util_8c.html + a3385ed559f3866d76ec4efaa2885daa4 + (const char *name, int status) + + + int + smaxScriptErrorAsync + smax-util_8c.html + af3acc2100069feec3a52475cdb24d479 + (const char *name, int status) + + + void + smaxSetOrigin + smax-util_8c.html + a9802443ba0d569c3614f5dcf8b0cfc4b + (XMeta *m, const char *origin) + + + int + smaxStringToValues + smax-util_8c.html + a9e3c024a1db97e7adc8a40694c657fd1 + (const char *str, void *value, XType type, int eCount, int *pos) + + + char * + smaxStringType + smax-util_8c.html + a8d9d92ad8825d4adad4d6288a5681351 + (XType type) + + + int + smaxTimestamp + smax-util_8c.html + ae56da599747b207813a710efc07dd47d + (char *buf) + + + __inline__ int + smaxTimeToString + smax-util_8c.html + a1c29c7229e7006aea4fc3eb6d4b4ee0e + (const struct timespec *time, char *buf) + + + void + smaxTransmitErrorHandler + smax-util_8c.html + a164a9c0f870cf0a1fa4f7e66f25452e5 + (Redis *redis, enum redisx_channel channel, const char *op) + + + XType + smaxTypeForString + smax-util_8c.html + af6a70e896526629e2130009882a1bff8 + (const char *type) + + + int + smaxUnpackStrings + smax-util_8c.html + a5665cd4f5087ab7a07239c30bc561173 + (const char *data, int len, int count, char **dst) + + + char * + smaxValuesToString + smax-util_8c.html + a4a80ebd309352379d3691f264282d96b + (const void *value, XType type, int eCount, char *trybuf, int trylength) + + + int + x2smaxField + smax-util_8c.html + a76bd110891905fe4bdae6628547c50d1 + (XField *f) + + + int + x2smaxStruct + smax-util_8c.html + a65cc6cdad09f861b968e2d492abed977 + (XStructure *s) + + + + smax.c + src/ + smax_8c.html + smax-private.h + + int + smaxAddConnectHook + smax_8c.html + ad63c425cc3affdf8bc803c7ff8dd6e30 + (void(*setupCall)(void)) + + + int + smaxAddDisconnectHook + smax_8c.html + a65ae161b28cfe4369709fae1d3ea678c + (void(*cleanupCall)(void)) + + + int + smaxAddSubscriber + smax_8c.html + a827dd87397943f3384605f87116b630c + (const char *idStem, RedisSubscriberCall f) + + + int + smaxConnect + smax_8c.html + a146fb2ed8512919dc91ecad6d08c74d1 + () + + + int + smaxConnectTo + smax_8c.html + ad960c22b119ff2493a319945a9dd55a5 + (const char *server) + + + int + smaxDisconnect + smax_8c.html + a9d1e6ffa837d3582a8165e326cc44bea + () + + + char * + smaxGetHostName + smax_8c.html + ac704fea3e664905af780d2566e3c74b6 + () + + + char ** + smaxGetKeys + smax_8c.html + a2544d1fa602e812004e1d68500024ae0 + (const char *table, int *n) + + + char * + smaxGetProgramID + smax_8c.html + abc07a7599e0bac1be15bbcb6b63d4710 + () + + + Redis * + smaxGetRedis + smax_8c.html + a533fbe770158afe876a3dafa78ba2195 + () + + + int + smaxIsConnected + smax_8c.html + a95cbb68e3eb751219ab3363c93a4840b + () + + + boolean + smaxIsPipelined + smax_8c.html + af6f57a699b784fc67534cff0abd9573b + () + + + boolean + smaxIsVerbose + smax_8c.html + a980232c82ed7ebf5425c60db65f828c0 + () + + + int + smaxKeyCount + smax_8c.html + a7030106bbe70220c97b1e9e3a4633ff4 + (const char *table) + + + int + smaxPull + smax_8c.html + afb7eec789669c3d3f416857d3615ace6 + (const char *table, const char *key, XType type, int count, void *value, XMeta *meta) + + + int + smaxReconnect + smax_8c.html + aafc75a2e8b8858b8ff0f16e0e73dbd03 + () + + + int + smaxReleaseWaits + smax_8c.html + a14bc33c30d27be9e2954ae7831099f1c + () + + + int + smaxRemoveConnectHook + smax_8c.html + a4708c3c699781abec237045c48719f3d + (void(*setupCall)(void)) + + + int + smaxRemoveDisconnectHook + smax_8c.html + a70cdc3f1bf6b97248b5b8ba6df4dc044 + (void(*cleanupCall)(void)) + + + int + smaxRemoveSubscribers + smax_8c.html + a77d04f4fbb447f169d40b2a24fa7cf71 + (RedisSubscriberCall f) + + + int + smaxSetAuth + smax_8c.html + a097b12d3bbb43175084b0b0a2f55339c + (const char *username, const char *password) + + + int + smaxSetDB + smax_8c.html + a79fba7411b5afa132457a6828ff5ed9f + (int idx) + + + void + smaxSetHostName + smax_8c.html + a886e2ed23987201a9808f1c99806b44a + (const char *name) + + + int + smaxSetPipelineConsumer + smax_8c.html + a542b4c264a49b61a6cd25881290df1d1 + (void(*f)(RESP *)) + + + int + smaxSetPipelined + smax_8c.html + a8d7a3f57360d8e505baa78e445a53875 + (boolean isEnabled) + + + int + smaxSetServer + smax_8c.html + a78cf94f007034f63b609cbe72b8047b0 + (const char *host, int port) + + + int + smaxSetTcpBuf + smax_8c.html + ac42ee8e8128aac0695c68660f04fd196 + (int size) + + + void + smaxSetVerbose + smax_8c.html + ac43709380b9ad92133a22ae0d52d107c + (boolean value) + + + int + smaxShare + smax_8c.html + aee07f085e12283ad96f42c4d77430880 + (const char *table, const char *key, const void *value, XType type, int count) + + + int + smaxShareArray + smax_8c.html + a1b116e8ffa85c30991ce6d8afb0319e0 + (const char *table, const char *key, const void *ptr, XType type, int ndim, const int *sizes) + + + int + smaxShareField + smax_8c.html + a0da1227278e6bc105c7dbdba14fd884a + (const char *table, const XField *f) + + + int + smaxShareStruct + smax_8c.html + ab6a1590c953abc1c37fed841cd3a903a + (const char *id, const XStructure *s) + + + int + smaxSubscribe + smax_8c.html + a53614ba57a594135c13b64a2d89eaa43 + (const char *table, const char *key) + + + int + smaxUnsubscribe + smax_8c.html + af3a5d7bc565ab7de0ac1dd8fafc93f14 + (const char *table, const char *key) + + + int + smaxWaitOnAnySubscribed + smax_8c.html + a89db98657eab826392d6099d21fff14c + (char **changedTable, char **changedKey, int timeout) + + + char * + GET_STRUCT + smax_8c.html + abc25cf33d9f3d6262a6fe3ffd94a85ae + + + + char * + HGET_WITH_META + smax_8c.html + ac5e36a13b5d67f497b15ab44b5a315af + + + + char * + HMSET_WITH_META + smax_8c.html + a561e3c013e65d6b0703bf1e574d7b821 + + + + char * + HSET_WITH_META + smax_8c.html + a6d21bc913aebbf4a95c6c4f6f18da3b4 + + + + + XCoordinateAxis + structXCoordinateAxis.html + + char * + name + structXCoordinateAxis.html + a5ac083a645d964373f022d03df4849c8 + + + + double + refIndex + structXCoordinateAxis.html + ad191af99a874bc633c0834d247427ea8 + + + + double + refValue + structXCoordinateAxis.html + ad56f22fc3fbf9639a29ed9f174c67ec2 + + + + double + step + structXCoordinateAxis.html + a4736138d712d9ee570d0652f08a4786a + + + + char * + unit + structXCoordinateAxis.html + a5a80171400807274a7fa9c95a104dc78 + + + + + XCoordinateSystem + structXCoordinateSystem.html + + XCoordinateAxis * + axis + structXCoordinateSystem.html + a5275f744c5bfc9a13b31a19c7ec5346c + + + + int + nAxis + structXCoordinateSystem.html + a66b674e84aa11d53a5f0763237b764ba + + + + + XMessage + structXMessage.html + + char * + host + structXMessage.html + a1c2046dcb30a629d6d9f45ff8f403f12 + + + + char * + prog + structXMessage.html + acc6113e98e7cd24d9dcfa520749a5d3f + + + + char * + text + structXMessage.html + a5633b1433389cec21ade3811bbe9ca5b + + + + double + timestamp + structXMessage.html + a2c17dfa2b3239f2312e94b9de57a7999 + + + + char * + type + structXMessage.html + a23506fc4821ab6d9671f3e6222591a96 + + + + + XMeta + structXMeta.html + + char + origin + structXMeta.html + a124de75960ce49e7d4dcbdad9237e128 + [SMAX_ORIGIN_LENGTH] + + + int + serial + structXMeta.html + a4f4017ce7a39a4da2ed1cf8c4dc7de3f + + + + int + status + structXMeta.html + a6e27f49150e9a14580fb313cc2777e00 + + + + int + storeBytes + structXMeta.html + a766b48fdc93d03992939adfa91766703 + + + + int + storeDim + structXMeta.html + a16e4b9723516717d3493c46157701520 + + + + int + storeSizes + structXMeta.html + adb4556a75a248cce0b72e557c81f8af6 + [X_MAX_DIMS] + + + XType + storeType + structXMeta.html + ace24d22a3441248636253cdb478de9f7 + + + + struct timespec + timestamp + structXMeta.html + a2aace03835c4d951b3dee117b328ef87 + + + + + XSyncPoint + structXSyncPoint.html + + pthread_cond_t * + isComplete + structXSyncPoint.html + a0b9f91194934aba0d7936d18d4bc81cc + + + + pthread_mutex_t * + lock + structXSyncPoint.html + a33586b4184d23f2b8f4df153ec23af13 + + + + int + status + structXSyncPoint.html + a6e27f49150e9a14580fb313cc2777e00 + + + + + md_CHANGELOG + Changelog + md_CHANGELOG.html + + + md_CONTRIBUTING + Contributing to RedisX + md_CONTRIBUTING.html + + + index + smax-clib + index.html + md_README-orig + introduction + prerequisites + building + configuration + connecting + connection-hooks + sharing-and-pulling + basics + metadata + flexible-types-and-sizes + scalars + arrays + structures + lazy-pulling + pipelined-pulls + lazy-synchronization + lazy-callbacks + lazy-finish + notifications + optional-metadata + error-handling + debug-support + future-plans + + diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md new file mode 100644 index 0000000..6f5756d --- /dev/null +++ b/doc/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +All notable changes to the [Smithsonian/redisx](https://github.com/Smithsonian/smax-clib) library will be +documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to +[Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + +## [Unreleased] + +Initial public release. diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 0000000..6a80d74 --- /dev/null +++ b/doc/README.md @@ -0,0 +1,730 @@ +![Build Status](https://github.com/Smithsonian/smax-clib/actions/workflows/build.yml/badge.svg) +![Static Analysis](https://github.com/Smithsonian/smax-clib/actions/workflows/check.yml/badge.svg) + + ![API documentation](https://github.com/Smithsonian/smax-clib/actions/workflows/dox.yml/badge.svg) + + + ![Project page](https://github.com/Smithsonian/smax-clib/actions/workflows/pages/pages-build-deployment/badge.svg) + + + + + + CfA logo + +
    + +# SMA-X: SMA information exchange + +Author: Attila Kovacs + +Last Updated: 14 September 2024 + +## Table of Contents + + - [Introduction](#introduction) + - [Prerequisites](#prerequisites) + - [Building the SMA-X C library](#building) + - [Initial configuration](#configuration) + - [Connecting to / disconnecting from SMA-X](#connecting) + - [Sharing and pulling data](#sharing-and-pulling) + - [Lazy pulling (high-frequency queries)](#lazy-pulling) + - [Pipelined pulls (high volume queries)](#pipelined-pulls) + - [Custom notification and update handling](#notifications) + - [Optional metadata](#optional-metadata) + - [Error handling](#error-handling) + - [Debug support](#debug-support) + - [Future plans](#future-plans) + +------------------------------------------------------------------------------ + + +## Introduction + +The SMA information eXchange (SMA-X) is a high performance and versatile data sharing platform for distributed software +systems. It is built around a central Redis database, and provides atomic access to structured data, including +specific branches and/or leaf nodes, with associated metadadata. + +SMA-X consists of a set of server-side [LUA](https://lua.org/) scripts that run on [Redis](https://redis.io) (or one +of its forks / clones such as [Valkey](https://valkey.io) or [Dragonfly](https://dragonfly.io)); a set of libraries to +interface client applications; and a set of command-line tools build with them. Currently we provide client libraries +for C/C++ and Python 3. We may provide Java and/or Rust client libraries too in the future. + + +------------------------------------------------------------------------------ + + +## Prerequisites + +The SMA-X C/C++ library has a build and runtime dependency on the __xchange__ and __RedisX__ libraries also available +at the Smithsonian Github repositories: + + - [Smithsonian/xchange](https://github.com/Smithsonian/xchange) + - [Smithsonian/redisx](https://github.com/Smithsonian/redisx) + +Additionally, to configure your Redis (or Valkey / Dragonfly) servers for SMA-X, you will need the +[Smithsonian/smax-server](https://github.com/Smithsonian/smax-server) repo also. + + +------------------------------------------------------------------------------ + + +## Building the SMA-X C library + +The __smax-clib__ library can be built either as a shared (`libsmax.so[.1]`) and as a static (`libsmax.a`) library, +depending on what suits your needs best. + +You can configure the build, either by editing `config.mk` or else by defining the relevant environment variables +prior to invoking `make`. The following build variables can be configured: + + - `XCHANGE`: the root of the location where the [Smithsonian/xchange](https://github.com/Smithsonian/xchange) library + is installed. It expects to find `xchange.h` under `$(XCHANGE)/include` and `libxchange.so` under `$(XCHANGE)/lib` + or else in the default `LD_LIBRARY_PATH`. + + - `REDISX`: the root of the location where the [Smithsonian/redisx](https://github.com/Smithsonian/redisx) library + is installed. It expects to find `redisx.h` under `$(REDISX)/include` and `libredisx.so` under `$(REDISX)/lib` + or else in the default `LD_LIBRARY_PATH`. + + - `CC`: The C compiler to use (default: `gcc`). + + - `CPPFLAGS`: C pre-processor flags, such as externally defined compiler constants. + + - `CFLAGS`: Flags to pass onto the C compiler (default: `-Os -Wall`). Note, `-Iinclude` will be added automatically. + + - `LDFLAGS`: Linker flags (default is `-lm`). Note, `-lredisx -lxchange` will be added automatically. + + - `BUILD_MODE`: You can set it to `debug` to enable debugging features: it will initialize the global `xDebug` + variable to `TRUE` and add `-g` to `CFLAGS`. + + - `CHECKEXTRA`: Extra options to pass to `cppcheck` for the `make check` target + +After configuring, you can simply run `make`, which will build the `shared` (`lib/libsmax.so[.1]`) and `static` +(`lib/libsmax.a`) libraries, local HTML documentation (provided `doxygen` is available), and performs static +analysis via the `check` target. Or, you may build just the components you are interested in, by specifying the +desired `make` target(s). (You can use `make help` to get a summary of the available `make` targets). + +------------------------------------------------------------------------------ + + + +## Initial configuration + +Bu default, the library assumes that the Redis server used for SMA-X runs on a machine called `smax` (e.g. you may assign +`smax` to the IP address in `/etc/hosts`), and that the Redis is on the default port 6379/tcp. However, you can configure +to use a specific host and/or an alternative Redis port number to use instead. + + +```c + smaxSetServer("my-smax.example.com", 7033); +``` + +Also, while SMA-X will normally run on database index 0, you can also specify a different database number to use. E.g.: + +```c + smaxSetDB(3); +``` + +(Note, you can switch the database later also, but beware that if you have an active subscription client open, you cannot +switch that client until the subscriptions are terminated.) + +You can also set up the authentication credentials for using the SMA-X database on the Redis server: + +```c + smaxSetUser("johndoe"); + smaxSetPassword("mySecretPassword); +``` + +And finally, you can select the option to automatically try reconnect to the SMA-X server in case of lost connection or +network errors (and keep track of changes locally until then): + +```c + smaxSetResilient(TRUE); +``` + +------------------------------------------------------------------------------ + + +## Connecting to / disconnecting from SMA-X + +Once you have configured the connection parameters, you can connec to the server by: + +```c + int status = smaxConnect(); + if(status < 0) { + // Oops, we could not connect to the server + ... + } +``` + +And, when you are done, you should disconnect with: + +```c + smaxDisconnect(); +``` + + +### Connection / disconnection hooks + +The user of the __smax-clib__ library might want to know when connections to the SMA-X server are established, or when +disconnections happen, and may want to perform some configuration or clean-up accordingly. For this reason, the +library provides support for connection 'hooks' -- that is custom functions that are called in the even of connecting +to or disconnecting from a Redis server. + +Here is an example of a connection hook, which simply prints a message about the connection to the console. + +```c + void my_connect_hook() { + printf("Connected to SMA-X server\n"); + } +``` + +And, it can be activated prior to the `smaxConnect()` call. + +```c + smaxAddConnectHook(my_connect_hook); +``` + +The same goes for disconnect hooks, using `smaxAddDisconnectHook()` instead. + + + +------------------------------------------------------------------------------ + + +## Sharing and pulling data + + - [The basics](#basics) + - [Standard metadata](#metadata) + - [Flexible types and sizes](#flexible-types-and-sizes) + - [Scalar quantities](#scalars) + - [Arrays](#arrays) + - [Structures / substructures](#structures) + + +### The basics + +For SMA-X we use the terms sharing and pulling, instead of the more generic get/set terminology. The intention is to +make programmers conscious of the fact that the transactions are not some local access to memory, but that they +involve networking, and as such may be subject to unpredictable latencies, network outages, or other errors. + +At the lowest level, the library provides two functions accordingly: `smaxShare()` and `smaxPull()`, either to send +local data to store in SMA-X, or to retrieve data from SMA-X for local use, respectively. There are higher-level +functions too, which build on these, providing a simpler API for specific data types, or extra features, such as +lazy or pipelined pulls. These will be discussed in the sections below. But, before that, let's look into the basics +of how data is handled between you machine local data that you use in your C/C++ application and its +machine-independent representation in SMA-X. + +Here is an example for a generic sharing of a `double[]` array from C/C++: + +```c + double data[8] = ... // your local data + + // Share (send) this data to SMA-X as "system:subsystem:some_data" + int status = smaxShare("system:subsystem", "some_data", X_DOUBLE, 8); + if(status < 0) { + // Ooops, that did not work... + ... + } + +``` + +Pulling data back from SMA-X works similarly, e.g.: + +```c + double data[4][2] = ... // buffer in which we will receive data + XMeta meta; // (optional) metadata we can obtain + + // Retrieve 'data' from the SMA-X "system:subsystem:some_data", as 8 doubles + int status = smaxPull("system:subsystem", "some_data", X_DOUBLE, 8, data, &meta); + if(status < 0) { + // Oops, something went wrong... + return; + } + +``` + +The metadata argument is optional, and can be `NULL` if not required. + + + +### Standard metadata + +For every variable (structure or leaf node) in SMA-X there is also a set of essential metadata that is stored in the +Redis database, which describe the data themselves, such as the native type (at the origin); the size as stored in +Redis; the array dimension and shape; the host (and program) which provided the data; the time it was last updated; +and a serial number. + +The user of the library has the option to retrieve metadata together with the actual data, and thus gain access to +this information. The header file `smax.h` defines the `Xmeta` type as: + + +```c + typedef struct XMeta { + int status; // Error code or X_SUCCESS. + XType storeType; // Type of variable as stored. + int storeDim; // Dimensionality of the data as stored. + int storeSizes[X_MAX_DIMS]; // Sizes along each dimension of the data as stored. + int storeBytes; // Total number of bytes stored. + char origin[SMAX_ORIGIN_LENGTH]; // Host name that last modified. + struct timespec timestamp; // Timestamp of the last modification. + int serial; // Number of times the variable was updated. + } XMeta; +``` + + +### Flexible types and sizes + +One nifty feature of the library is that as a consumer you need not be too concerned about what type or size of data +the producer provides. The program that produces the data may sometimes change, for example from writing 32-bit +floating point types to a 64-bit floating point types. Also while it produced data for say 10 units before (as an +array of 10), now it might report for just 9, or perhaps it now reports for 12. + +The point is that if your consumer application was written to expect ten 32-bit floating floating point values, it can +get that even if the producer changed the exact type or element count since you have written your client. The library +will simply apply the necessaty type conversion automatically, and then truncate, or else pad (with zeroes), the data +as necessary to get what you want. + +The type conversion can be both widening or narrowing. Strings and numerical values can be converted to one another +through the expected string representation of numbers and vice versa. Boolean `true` values are treated equivalently +to a numerical value of 1 and all non-zero numerical values will convert to boolean `true`. + +And, if you are concerned about the actual type or size (or shape) of the data stored, you have the option to inspect +the metadata, and make decisions based on it. Otherwise, the library will just take care of giving you the available +data in the format you expect. + + + +### Scalar quantities + +Often enough we deal with scalar quantities (not arrays), such as a single number, boolean value, or a +string (yes, we treat strings i.e., `char *`, as a scalar too!). + +Here are some examples of sharing scalars to SMA-X. Easy-peasy: + +```c + int status; + + // Put a boolean value into SMA-X + status = smaxShareBoolean("system:subsystem", "is_online", TRUE); + + // Put an integer value into SMA-X + status = smaxShareInt("system:subsystem", "some_int_value", 1012); + + // Put a floating-point value into SMA-X + status = smaxShareDouble("system:subsystem", "some_value", -3.4032e-11); + + // Put a string value into SMA-X + status = smaxShareString("system:subsystem", "name", "blah-blah"); +``` + +Or pulling them from SMA-X: + +```c + // Retrieve "system:subsystem:is_online" as a boolean, defaulting to FALSE + boolean isTrue = smaxPullBoolean("system:subsystem", "is_online", FALSE); + + // Retrieve "system:subsystem:some_int_value" as an int, with a default value of -1 + int c = smaxPullInt("system:subsystem", "some_int_value", -1); + + // Retrieve "system:subsystem:some_value" as a double (or else NAN if cannot). + double value = smaxPullDouble("system:subsystem", "some_value"); + if(!isnan(value)) { // check for NAN if need be + ... + } + + // Retrieve "system:subsystem:name" as a 0-terminated C string (or NULL if cannot). + char *str = smaxPullDouble("system:subsystem", "name"); + if(str != NULL) { // check for NULL + ... + } + + ... + + // Once the pulled string is no longer needed, destroy it. + free(str) + +``` + + +### Arrays + +The generic `smaxShare()` function readily handles 1D arrays, and the `smaxPull()` handles native (monolithic) arrays +of all types (e.g. `double[][]`, or `boolean[][][]`). However, you may want to share multidimensional arrays, noting +their specific shapes, or else pull array data for which you may not know in advance what size (or shape) of the +storage needed locally for the values stored in SMA-X for some variable. For these reasons, the library provides a set +of functions to make the handling of arrays a simpler too. + +Let's begin with sharing multi-dimensional arrays. Instead of `smaxShare()`, you can use `smaxShareArray()` which +allows you to define the multi-dimensional shape of the data beyond just the number of elements stored. E.g.: + +```c + float data[4][2] = ... // Your local 2D data array + int shape[] = { 4, 2 }; // The array shape as stored in SMA-X + + int status = smaxShareArray("system:subsystem", "my_2d_array", X_FLOAT, 2, shape); + if (status < 0) { + // Oops, did not work... + ... + } +``` + +Note, that the dimensions of how the data is stored in SMA-X is determined solely by the '2' dimensions specified +as the 4th argument and the corresponding 2 elements in the `shape` array. The `data` could have been any pointer +to an array of floats containing at least the required number of element (8 in the example above). + +For 1D arrays, you have some convenience methods for sharing specific types. These can be convenient because they +eliminate one potential source of bugs, where the type argument to `smaxShare()` does not match the pointer type of +the data. Using, say, `smaxShareFloats()` instead to share a 1D floating-point array instead of the generic +`smaxShare()` will allow the compiler to check and warn you if the data array is not the `float *` type. E.g.: + +```c + float *data = ... // pointer to a one or higher-dimensional C array of floats. + + // Send N elements from data to SMA-X as "system:subsystem:my_array" + int status = smaxShareFloats("system:subsystem", "my_array", data, N); + if (status < 0) { + // Oops, did not work... + ... + } +``` + +Similar functions are available for every built-in type (primitives, plus strings and booleans). For pulling arrays +without knowing a-priori the element count or shape, there are also convenience functions, such as: + +```c + XMeta meta; // (optional) we'll return the metadata in this + int status; // we'll return the status in this + + // Get whatever data is in "system:subsystem:my_array" as doubles. + double *data = smaxPullDoubles("system:subsystem", "my_array", &meta, &status); + if(status < 0) { + // Oops, we got an error + } + if(data == NULL) { + // Oops the data is NULL + } + + ... + + // When done using the data we obtained, destroy it. + free(data); +``` + +As illustrated, the above will return a dynamically allocated array with the required size to hold the data, and the +size and shape of the data is returned in the metadata that was also supplied with the call. After using the returned +data (and ensuring that it is not `NULL`), you should always call `free()` on it to avoid memory leaks in your +application. + + +### Structures / substructures... + +You can share entire data structures, represented by an appropriate `XStructure` type (see the __xchange__ library for +a description and usage): + +```c + XStructure s = ... // The structured data you have prepared locally. + + int status = smaxShareStruct("syste:subsystem", &s); + if(status < 0) { + // Oops, something did not work + ... + } +``` + +Or, you can read a structure, including all embedded substructures in it, with `smaxPullStruct()`: + + +```c + XMeta meta; + int nElements; + + XStructure *s = smaxPullStruct("system", "subsystem", &meta, &n); + if(n < 0) { + // Oops there was an error... + return; + } + + double value = smaxGetDoubleField(s, "some_value", 0.0); + + ... + + // Once the pulled structure is no longer needed, destroy it... + xDestroyStruct(s); +``` + +Note, that the structure returned by `smaxPullStruct()` is in the serialized format of SMA-X. That is, all leaf nodes +are stored as strings, just as they appear in the Redis database. Hence, we used the `smaxGet...Field()` methods above +to deserialize the leaf nodes as needed on demand. If you want to use the methods of __xchange__ to access the +structure, you will need to convert to binary format first, using `smax2xStruct(XStructure *)`. + +Note also, that pulling large structures can be an expensive operation on the Redis server, and may block the server +for longer than usual periods, causing latencies for other programs that use SMA-X. It's best to use this method for +smallish structures only (with, say, a hundred or so or fewer leaf nodes). + + +------------------------------------------------------------------------------ + + +## Lazy pulling (high-frequency queries) + +What happens if you need the data frequently? Do you pound on the database at some high-frequency? No, you probably +no not want to do that, especially if the data you need is not necessaily changing fast. There is no point on wasting +network bandwidth only to return the same values again and again. This is where 'lazy' pulling excels. + +From the caller's perspective lazy pulling works just like regular SMA-X pulls, e.g.: + +```c + int data[10][4][2]; + int sizes[] = { 10, 4, 2 }; + XMeta meta; + + int status = smaxLazyPull("some_table", "some_data", X_INT, 3, sizes, data, &meta); +``` + +or + +```c + int status = smaxLazyPullDouble("some_table", "some_var"); +``` + +But, under the hood, it does something different. The first time a new variable is lazy pulled it is fetched from the +Redis database just like a regular pull. But, it also will cache the value, and watch for update notifications from +the SMA-X server. Thus, as long as no update notification is received, successive calls will simply return the locally +cached value. This can save big on network usage, and also provides orders of magnitude faster access so long as the +variable remains unchanged. + +When the vatiable is updated in SMA-X, our client library will be notified, and one of two things can happen: + + 1. it invalidates the cache, so that the next lazy pull will again work just like a regular pull, fetching the + updated value from SMA-X on demand. And again the library will cache that value and watch for notifications for + the next update. Or, + + 2. it will trigger a background process to update the cached value in the background with a pipelined + (high-throughput) pull. However, until the new value is actually fetched, it will return the previously cached + value promptly. + +The choice between the two is yours, and you can control which suits your need best. The default behavior for lazy pulls +is (1), but you may call `smaxLazyCache()` after the first pull of a variable, to indicate that you want to enable +background cache updates (2) for it. The advantage of (1) is that it will never serve you outdated data even if there +are significant network latencies -- but you may have to wait a little to fetch updates. On the other hand (2) will +always provide a recent value with effectively no latency, but this value may be outdated if there are delays on the +network updating the cache. The difference is typically at the micro-seconds level on a local LAN. However, (2) may +be preferable when you need to access SMA-X data from timing critical code blocks, where it is more important to ensure +that the value is returned quickly, rather than whether it is a millisecond too old or not. + +In either case, when you are done using lazy variables, you should let the library know that it no longer needs to watch +updates for these, by calling either `smaxLazyEnd()` on specific variables, or else `smaxLazyFlush()` to stop watching +updates for all lazy variables. (A successive lazy pull will automatically start watching for updates again, in case you +wish to re-enable). + +```c + // Lazy pull a bunch of data (typically in a loop). + for(...) { + smaxLazyPull("some_table", "some_var", ...); + smaxLaxyPull(...); + ... + } + + // Once we do not need "some_table:some_var" any more: + smaxLazyEnd("some_table", "some_var"); + + ... + + // And to stop lazy accessing all + smaxLazyFlush(); +``` + + +------------------------------------------------------------------------------ + + +## Pipelined pulling (high volume queries) + + - [Synchronization points and waiting](#lazy-synchronization) + - [Callbacks](#lazy-callbacks) + - [Finishing up](#lazy-finish) + +The regular pulling of data from SMA-X requires a separate round-trip for each and every request. That is, successive +pulls are sent only after the responses from the prior pull has been received. A lot of the time is spent on waiting +for responses to come back. With round trip times in the 100 μs range, this means that this method of fetching data +from SMA-X is suitable for obtaining at most a a few thousand values per second. + +However, sometimes you want to get access to a large number of values faster. This is what pipelined pulling is for. +In pipelined mode, a batch of pull requests are sent to the SMA-X Redis server in quick succession, without waiting +for responses. The values, when received are processed by a dedicated background thread. And, the user has an option +of either waiting until all data is collected, or ask for as callback when the data is ready. + +Again it works similarly to the basic pulling, except that you submit your pull request to a queue with +`smaxQueue()`. For example: + +```c + double d; // A value we will fill + XMeta meta; // (optional) metadata to fill (for the above value). + + int status = smaxQueue("some_table", "some_var", X_DOUBLE, 1, &d, &meta); +``` + +Pipelined (batched) pulls have dramatic effects on performance. Rather than being limited by round-trip times, you will +be limited by the performance of the Redis server itself (or the network bandwidth on some older infrastructure). As +such, instead of thousand of queries per second, you can pull 2-3 orders of magnitude more in a given time, with hudreds +of thousands to even millions of pull per second this way. + + +### Synchronization points and waiting + +After you have submitted a batch of pull request to the queue, you can create a synchronization point as: + +```c + XSyncPoint *syncPoint = smaxCreateSyncPoint(); +``` + +A synchronization point is a marker in the queue that we can wait on. After the synchronization point is created, you +can sumbit more pull request to the same queue (e.g. for another processing block), or do some other things for a bit +(since it will take at least some microseconds before the data is ready). Then, when ready you can wait on the +specific synchronization point to ensure that data submitted prior to its creation is delivered from SMA-X: + +```c + // Wait for data submitted prior to syncPoint to be ready, or time out after 1000 ms. + int status = smaxSync(syncPoint, 1000); + + // Destroy the synchronization point if we no longer need it. + xDestroySyncPoint(syncPoint); + + // Check return status... + if(status == X_TIMEOUT) { + // We timed out + ... + } + else if(status < 0) { + // Some other error + ... + } +``` + + +### Callbacks + +The alternative to synchronization points and waiting, is to provide a callback function, which will process your data +as soon as it is available, e.g.: + +```c + void my_pull_processor(void *arg) { + // Say, we expect a string tag passed along to identify what we need to process... + char *tag = (char *) arg; + + // Do what we need to do... + ... + } +``` + +Then submit this callback routine to the queue after the set of variables it requires with: + +```c + // We'll call my_pull_processor, with the argument "some_tag", when prior data has arrived. + smaxQueueCallback(my_pull_processor, "some_tag"); +``` + + +### Finishing up + +If you might still have some pending pipelined pulls that have not received responses yet, you may want to wait until +all previously sumbitted requests have been collected. You can do that with: + +```c + // Wait for up to 3000 ms for all pipelined pulls to collect responses from SMA-X. + int status = smaxWaitQueueComplete(3000); + + // Check return status... + if(status == X_TIMEOUT) { + // We timed out + ... + } + else if(status < 0) { + // Some other error + ... + } +``` + + + +------------------------------------------------------------------------------ + + +## Custom notifications and update handling + +### Monitoring updates + +### Waiting for updates + +### Status / error messages + + +------------------------------------------------------------------------------ + + +## Optional metadata + + +### Descriptions + +### Coordinate Systems + +### Physical units + +#### Coordinate systems + + + +----------------------------------------------------------------------------- + + +## Error handling + +The principal error handling of the library is an extension of that of __xchange__, with further error codes defined +in `smax.h` and `redisx.h`. The functions that return an error status (either directly, or into the integer designated +by a pointer argument), can be inspected by `smaxErrorDescription()`, e.g.: + +```c + int status = smaxShare(...); + if (status != X_SUCCESS) { + // Ooops, something went wrong... + fprintf(stderr, "WARNING! set value: %s", smaxErrorDescription(status)); + ... + } +``` + +----------------------------------------------------------------------------- + + +## Debug support + +You can enable verbose output of the library with `smaxSetVerbose(boolean)`. When enabled, it will produce status +messages to `stderr`so you can follow what's going on. In addition (or alternatively), you can enable debug messages +with `xSetDebug(boolean)`. When enabled, all errors encountered by the library (such as invalid arguments passed) will +be printed to `stderr`, including call traces, so you can walk back to see where the error may have originated from. +(You can also enable debug messages by default by defining the `DEBUG` constant for the compiler, e.g. by adding +`-DDEBUG` to `CFLAGS` prior to calling `make`). + +For helping to debug your application, the __xchange__ library provides two macros: `xvprintf()` and `xdprintf()`, +for printing verbose and debug messages to `stderr`. Both work just like `printf()`, but they are conditional on +verbosity being enabled via `xSetVerbose(boolean)` and `xSetDebug(boolean)`, respectively. Applications using this +library may use these macros to produce their own verbose and/or debugging outputs conditional on the same global +settings. + + + +----------------------------------------------------------------------------- + + +## Future plans + +Some obvious ways the library could evolve and grow in the not too distant future: + + - Automated regression testing and coverage tracking. + +If you have an idea for a must have feature, please let me (Attila) know. Pull requests, for new features or fixes to +existing ones, are especially welcome! + +----------------------------------------------------------------------------- +Copyright (C) 2024 Attila Kovács + diff --git a/doc/resources b/doc/resources new file mode 120000 index 0000000..5548311 --- /dev/null +++ b/doc/resources @@ -0,0 +1 @@ +../resources/ \ No newline at end of file diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..cba92a6d38b06c6de96a3b82587a453d830154eb GIT binary patch literal 15406 zcmeI3cX*Xmp2uGp$FWdCl_DJxkP<9dM^SWafTOH}b#04Ck$^}EB&0$LC7mQBq#-B} zdgw)GXI*EW-5njBu`@b4jsrL<=z^d*`~94I&&|D;011R=|1r<=KJR4#=&D@!ri#Z2f&+V%zU|PD$yTHzn)dfhPj8aI$xPMXZ+}l|AyuN!kBm^lYYO z++nZy^ugwuRclPioS*+#9^(}-HW&`S)8}2Xr+ChJCOIwAblmnA^Fqd*X4KMI=7FWN z&BMjh%-t0k7H09BUzoJHm%b7V1H8PyZsp5n&irf5$dUxpV)xgk|N2+W;K~i=vJL-X ze);lpeY-|uRvN}K2O1`dC+LFSxcOI`=6k+1S5T0!_#~Ft!#L$g%H+*UUp&&p7FXbm85(DgATM z7uI}aX@a?G^~Mvz=u!2ixl!wQcf}&8)nd2uZUL}lOiBYMNyuzo$N-tfs0S+Itp z1-N`;4D_<*Q?iCxeJ-2r^k=30j;^3H@QO^}>pszjexPIMX@%xE9WIIU&P%iUYxT;~ zht8tEtP8S%KlBFOL)U}#7dXIx4(LLkuo-7R&^sx6q`|iA7>#wf!|#(aMhr+v>662{ zus&{$=BD+}$%=_Mq5X!#sq1h2Ojlh)bm5=Q^lw?5*Q{)oHwr%?{r9Fl%b4BH5 zlbg^QJ33MpZ|34{d#(NO%++P< z`*xgkI~2dhm&G*tM^VBBgH9#~%eQbpS~$rpOzvu7f`7r>?xy|rPp!}BuX7>jS<+FkNXy{s(oeZa?G4_LP+;E&PIOE&#a;2VBTzRX0f-D$@{ z127$Y^g0-S5&9-w4SZ+4MEjt%+bztNyS_4yESX|`Civ}z5BEPe-}7BSHu%%g#WM|a z_zn$Dh8Di)u(;xC)?rNk(*-$+ZEENfe#Xw9+e2{vY2mgd?-9Gc3D5!! z$icxH@=}@UxBlPFh_Y0JPeBI7)4Zk=az-7xe9aa!FXb{~r-_mNj9vV=&2>i0zQG-i z=TyI$^XQVv(mBsOpE=C5+x|BTr?1v+3=q}`UUHkFRzdf`I(gm`hY)|Z1Ry$>by&BF4$$udjUH-6_54# zj$h16Xc@A`qM<-G_dD=&K@%6YOkC}?>A!unJDod?J2LFP`EBKN1FYY2xa{2*#|{L) z13&&`O6CZIU6GsAhtH6)vXKF6cUxY73G858^2-N^pEDN?RV?p?C! z4`yP{1Ew&pNkG3HzoLgcYO(vxo%l+OYlwAsFj#-|xbxNz%;44Q4S9;?75kgz-S6Z= zet`~SF_;@$kXsY_+RV~9_*}KWdJJ}F#fx}$#C}5FK@=o?%YyJftzIAZX zk~-MgGmdLZ|DO$DO^W#65E<9l%J6crKa=_@I)LTZaUoVes5`#jor*Gi}g~%Yx;0pC;JWE zV-`P=KQVXILGm<*gS)Li7Y+@1hio2O5_K>qp>08Zc|I8(_({L7UaYlwUHJFQhaThN znRmjySn=zA#-0q;Pv2@JK%WGocwARQ^hpHfxIZJ%MU%aj^drhSn{BP6_cgY_m>BN|U7v}kwH33xsY|21%l8Q8Sti?pm+U$&i}6ZS z(|vx~y5Ag~Kd)!C=%}GDh<;)wxqb-!{_n-H=c=B6wECu(%8%Z*yx@zZ)X37MGraC+ zi-#rA-bK=n$y)y}i{dV*CRgdY`5nca3y!BtBA^#+>d|Z<*wj{-N_@yraTZrC!F6Go?Sy^BPOfpBCPI!f*E+ z(1q!Xer4M2_?u$>LGyUQcvGr;BA9lb={=K|wcYtepob0pGgQ;HQ_qT+dF%3m+SgAu zqOk{-&Gsfj!|Cv`GR`}s6=c+E`iSgpEXKRncD9i;E*%(q#|9jXT_FB+TssO_%+6WMTI93LSY z++yjldmhTwFI)dx<%iu&aol-<-YRqsd8t%%HZ`Sl&N0I)7Sz;X>RFLvI(a+T^l~O@ zO(WNAw>${nchcJlbr*h{;0e?6@xtr;{t@X2C)HnQX5o^Pjx33n9oO`7n(sbjqB4K& z>nr>F3-p*%=k-=?akqcZ4EmLGt0zWH2#vrTC)>D8Ytn4@ca{g&Q-e3rg&tS=eQT{t zA>TVeV~*PK%+UpG<&2V{bP~Um8Yw7E?=|F>b|SPn#u;y!7f|g z30bR1)nV#)nykcjw!WvQ3J!Q+9l#w-i+DJy+2k4dEGRFPpx#dou&vEat?cwF=W_-?Q#fXmrYtPJsPx>tAl3V+txbsb-_959@OwhhFv0t&R6q+3mWiz}%cP-1>J8Qv> z$FG^651$^jHk~)W8-lOdp2JpO>q@s9*F^K&Ub}rK+B<3;&?TogdGRe2t6wq~DOM6o z+V1$f)vct|fnUf+x;>vp()%g5znFKpr}_u_rkL2o#ua=s`hkz&$`nStO{J6c zl!r=Bh>bTZzOcrfmBUb<4_vp)43p0GU&p?^o5ZJTREAF~JqXyFbCfW55*h`N3XE$gsgPg{fyQnXxxN2ef zW6l}Nx*j}ZTbwhYFJygCkWYbT>HR(OMKkry`W^Tpzl~lvM1Ji-^Q8J?Bg#|lUK!^| ze0&^#PUURy1TJC@aSys`p}*SJtFu+Z1@VQiWW2jd6=TVDre@x0daCDrws`=4#IA$p z))xy*w&JFxCy2gaTD1mMqVvxo@BCw-pPUgNlr0~G9Ml^&t#<5hIJ*tkCFLlQYj!9f zA7wIBquHE~ytOv@LuZWlzOJuz+1OU5I*(c@ZvJ3PEA=aVYy1s4Ou(+f@ix$JySCE# z_UhA<^O3i**GT=qIUZ=UwUVD+$^DzcxTeQmSagTZQ6yPCXP>F<&c7S<9bW@XmoJ_T zJwFjlo4X3P^>>Q%)N$0J>^;#FpzlqOO}2eBT78buMKjE`t5!?L-%#DRSGmsqfV}@- z>6b6X7eW*Eca3@i=motQ>DN)&$5+AnL){&(`g~%}D0?1i=<;IAbBFDJ4e)a!nVso- z)*2lJSAWG#;wNXaCde0})6f>KKeCOtPh`Ku49-<(b$^T=wHr%n1sXC8~K9WNr6ZQq^NA+F*n$5wR*I~~xSgt2~ZX!S3O8&0qypOMT z18?{>NIi+dIkso{34L$!=Y?~-SEkMDRZX5m-1F_t?G4POuAolmtZ+_38{7NAPn?XV zdVN!lX!WHmo!s7ZRh>+2&%2>3ifo-pf2l{+A8pTcY~CaEu-Cje!_#SQuTf&kfJuWY zw;t}I+6ozSF30h0&uOW4q1V9LOvxCo{JCLsIdHYm`KD)8rog-V$S{nC@>O_5?AzM#O zyWG$xbap{5MLdCKs~c8kU;Art*-4#k)0cl=y7Bkw-xk`sF<2h-W?cOq?o;?ppFJsM zU`cTOZr4C|EL!(TuWT+CJQpAQjLr@c$DtD*SO;PnJ&<5q;9G0eOaVUqa zgg@pSf}@o?HQ@6ZcZcuKi5pb5F*tLV3|E}SE^Ik4(xp5f{CimZ^eqVJfP8X15GYF@T)q%IYu?(zKrC~ z$L(J@`k|BlAv6*@pC}k-^DS~l@?LZV|4P2@_AjVI=_!y8IR4lVqp#!O`sHode_#(q zK4(%~J@=9DPw>Dx1j7w}Caw%GpKoOuzE7mHv+`H_Z5>D5j9k$V?&$oi1vlAP0}mH% z|6IMzD?;e^^YE?CX*?rZ&aF+(r+R1CVV3u>aDEbO(~bw|AjUyMYxxf9IOyX$|Kmf= zM9(r_wTGMI?yS+%i=Q^Fv=`P&K8-y=>$~C6XRDveA3j-Mx!1;%-=;T;wt#PiPJCSV z&2L%yuUfsq#(rcBjlTWUH|)7h@&QM;yE7k~?yj5$9@&$He!V}cYh&pw@5b6_Io)^o zR>8M>sr1=7H$@Dk9^-#~vPB~_Ir`{jT&w>XqJEJ62Hv~x+}Zo?z43Q8r;#mTr~8!` zj04x{(s`I{1I z)vMMYPD$;zSGtm2Hr?xdD*O%c-R4WtUO(l4&&jVIu@3lu8uF6_&PW3P2d8%UPXGV_ literal 0 HcmV?d00001 diff --git a/index.md b/index.md new file mode 100644 index 0000000..fa5a046 --- /dev/null +++ b/index.md @@ -0,0 +1,41 @@ +--- +excerpt: C/C++ client library for SMA-X structured data exchange. +--- + +CfA logo
    + +The SMA information eXchange (SMA-X) is a high performance and versatile data sharing platform for distributed software +systems. It is built around a central Redis database, and provides atomic access to structured data, including +specific branches and/or leaf nodes, with associated metadadata. The lead architect of SMA-X is Attila Kovács at the +Center for Astrophysics \| Harvard & Smithsonian. + +The __smax-clib__ C/C++ client library was created, and is maintained, by Attila Kovács at the Center for Astrophysics +\| Harvard & Smithsonian, and it is available through the +[Smithsonian/redisx](https://github.com/Smithsonian/smax-clib) repository on GitHub. + +This site contains various online resources that support the library: + +__Dependencies__ + + - [Smithsonian/xchange](https://github.com/Smithsonian/xchange) -- structured data exchange framework + - [Smithsonian/redisx](https://github.com/Smithsonian/redisx) -- A C/C++ Redis client library + - [Smithsonian/smax-server](https://github.com/Smithsonian/smax-server) -- SMA-X server configuration kit + +__Downloads__ + + - [Releases](https://github.com/Smithsonian/smax-clib/releases) from GitHub + - Doxygen [tag file](apidoc/smax.tag) (`smax.tag`) for linking + your [Doxygen](https://www.doxygen.nl/) documentation to that of __smax-clib__ + + +__Documentation__ + + - [User's guide](doc/README.md) (`README.md`) + - [API Documentation](apidoc/html/files.html) + - [History of changes](doc/CHANGELOG.md) (`CHANGELOG.md`) + - [Issues](https://github.com/Smithsonian/smax-clib/issues) affecting __smax-clib__ releases (past and/or present) + - [Community Forum](https://github.com/Smithsonian/smax-clib/discussions) – ask a question, provide feedback, or + check announcements. + + + diff --git a/resources/CHANGELOG.md b/resources/CHANGELOG.md new file mode 100644 index 0000000..542d4f8 --- /dev/null +++ b/resources/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +All notable changes to the RedisX [Smithsonian/redisx](https://github.com/Smithsonian/redisx) library will be +documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to +[Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + +## [Unreleased] + +Initial public release. diff --git a/resources/CfA-logo.png b/resources/CfA-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f0ca7e0bb709447781d65709ce64fcbd8b5a8988 GIT binary patch literal 66776 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 + ![API documentation](https://github.com/Smithsonian/redisx/actions/workflows/dox.yml/badge.svg) + + + ![Project page](https://github.com/Smithsonian/redisx/actions/workflows/pages/pages-build-deployment/badge.svg) + + + + + + CfA logo + +
    + + +# RedisX + +A simple, light-weight C/C++ Redis client. + +## Table of Contents + + - [Introduction](#introduction) + - [Prerequisites](#prerequisites) + - [Building RedisX](#building-redisx) + - [Managing Redis server connections](#managing-redis-server-connections) + - [Simple Redis queries](#simple-redis-queries) + - [Atomic execution blocks and LUA scripts](#atomic-transaction-blocks-and-lua-scripts) + - [Publish/subscribe (PUB/SUB) support](#publish-subscribe-support) + - [Implementing further Redis commands](#implementing-further-redis-commands) + - [Error handling](#error-handling) + - [Debug support](#debug-support) + - [Future plans](#future-plans) + + + +## Introduction + +__RedisX__ is a light-weight [Redis](https://redis.io) client for C/C++. As such, it should also work with Redis forks +/ clones like [Dragonfly](https://dragonfly.io) or [Valkey](https://valkey.io). It supports both interactive and +pipelined Redis queries, managing and processing subscriptions. It also supports atomic execution blocks and LUA +scripts loading. It can be used with one or more distinct Redis servers simultaneously. + +While there are other C/C++ Redis clients available, this one is C90 compatible, and hence can be used on older +platforms also. It is also small and fast, but still capable and versatile. + +Rather than providing high-level support for every possible Redis command (which would probably be impossible given +the pace new commands are being introduced all the time), it provides a basic framework for synchronous and +asynchronous queries, with some higher-level functions for managing key/value storage types (including hash tables), +and PUB/SUB. Future releases may add further higher-level functionality based on demand for such features. + +The library maintains up to three separate connections (channels) for each separate Redis server instance used: (1) an +interactive client for sequential round-trip transactions, (2) a pipeline client for bulk queries and asynchronous +background processing, and (3) a subscription client for PUB/SUB requests and notofocations. The interactive client is +always connected, the pipeline client is connected only if explicitly requested at the time of establishing the server +connection, while the subscription client is connected only as needed. + +The __RedisX__ library was created, and is maintained, by Attila Kovács at the Center for Astrophysics \| Harvard +& Smithsonian, and it is available through the [Smithsonian/redisx](https://github.com/Smithsonian/redisx) +repository on GitHub. + +There are no official releases of __RedisX__ yet. An initial 1.0.0 release is expected in late 2024 or early 2025. + +----------------------------------------------------------------------------- + + +## Prerequisites + +The [Smithsonian/xchange](https://github.com/Smithsonian/xchange) library is both a build and a runtime dependency of +RedisX. + +----------------------------------------------------------------------------- + + +## Building RedisX + +The RedisX library can be built either as a shared (`libredisx.so[.1]`) and as a static (`libredisx.a`) library, +depending on what suites your needs best. + +You can configure the build, either by editing `config.mk` or else by defining the relevany environment variables +prior to invoking `make`. The following build variables can be configured: + + - `XCHANGE`: the root of the location where the [Smithsonian/xchange](https://github.com/Smithsonian/xchange) is + installed. It expects to find `xchange.h` under `$(XCHANGE)/include` and `libxchange.so` under `$(XCHANGE)/lib` + or else in the default `LD_LIBRARY_PATH`. + + - `CC`: The C compiler to use (default: gcc). + + - `CPPFLAGS`: C pre-processor flags, such as externally defined compiler constants. + + - `CFLAGS`: Flags to pass onto the C compiler (default: -Os -Wall). Note, `-Iinclude` will be added automatically. + + - `LDFLAGS`: Linker flags (default is `-lm`). + + - `CHECKEXTRA`: Extra options to pass to `cppcheck` for the `make check` target + +After configuring, you can simply run `make`, which will build the `shared` (`lib/libxchange.so[.1]`) and `static` +(`lib/libxchange.a`) libraries, local HTML documentation (provided `doxygen` is available), and performs static +analysis via the `check` target. Or, you may build just the components you are interested in, by specifying the +desired `make` target(s). (You can use `make help` to get a summary of the available `make` targets). + + +----------------------------------------------------------------------------- + + +## Managing Redis server connections + + - [Initializing](#initializing) + - [Connecting](#connecting) + - [Disconnecting](#disconnecting) + - [Connection hooks](#connection-hooks) + + +### Initializing + +The first step is to create a `Redis` object, with the server name or IP address. + +```c + // Configure the redis server to connect to "redis.mydomain.com". + Redis *redis = redisxInit("redis.mydomain.com"); + if (redis == NULL) { + // Abort: something did not got to plan... + return; + } +``` + +Before connecting to the Redis server, you may configure optional settings, such as the TCP port number to use (if not +the default 6379), and the database authentication password (if any): + +```c + Redis *redis = ... + + // (optional) configure a non-standard port number + redisxSetPort(&redis, 7089); + + // (optional) Configure the database password... + redisxSetPassword(&redis, mySecretPasswordString); +``` + +You might also tweak the send/receive buffer sizes to use for clients, if you find the socket defaults sub-optimal for +you application: + +```c + // (optional) Set the TCP send/rcv buffer sizes to use if not default values. + // This setting applies to all new connections after... + redisxSetTcpBuf(65536); +``` + + +### Connecting + +Once configured, you can connect to the server as: + +```c + // Connect to Redis, including a 2nd dedicated client for pipelined requests + int status = redisxConnect(&redis, TRUE); + if (status != X_SUCCESS) { + // Abort: we could not connect for some reason... + ... + // Clean up... + redisxDestroy(&redis); + ... + } +``` + +The above will establish both an interactive connection and a pipelined connection client, for processing both +synchronous and asynchronous requests (and responses). + + +### Disconnecting + +Whne you are done with a specific Redis server, you should disconnect from it: + +```c + Redis *redis = ... + + redisxDisconnect(redis); +``` + + +### Connection hooks + +The user of the __RedisX__ library might want to know when connections to the server are established, or when +disconnections happen, and may want to perform some configuration or clean-up accordingly. For this reason, the +library provides support for connection 'hooks' -- that is custom functions that are called in the even of connecting +to or disconnecting from a Redis server. + +Here is an example of a connection hook, which simply prints a message about the connection to the console. + +```c + void my_connect_hook(Redis *redis) { + printf("Connected to Redis server: %s\n", redis->id); + } +``` + +And, it can be added to a Redis instance, between the `redisxInit()` and the `redisxConnect()` calls. + +```c + Redis *redis = ... + + redisxAddConnectHook(redis, my_connect_hook); +``` + +The same goes for disconnect hooks, using `redisxAddDisconnectHook()` instead. + +----------------------------------------------------------------------------- + + +## Simple Redis queries + + - [RESP data type](#resp-data-type) + - [Interactive transactions](#interactive-transactions) + - [Pipelined transactions](#pipelined-transactions) + +Redis queries are sent as strings, according the the specification of the Redis protocol. All responses sent back by +the server using the RESP protocol. Specifically, Redis uses version 2.0 of the RESP protocol (a.k.a. RESP2) by +default, with optional support for the newer RESP3 introduced in Redis version 6.0. The RedisX library currently +processes the standard RESP2 replies only. RESP3 support to the library may be added in the future (stay tuned...) + + +### RESP data type + +All responses coming from the Redis server are represented by a dynamically allocated `RESP` type (defined in +`redisx.h`) structure. Each `RESP` has a type (e.g. `RESP_SIMPLE_STRING`), an integer value `n`, and a `value` pointer +to further data. If the type is `RESP_INT`, then `n` represents the actual return value (and the `value` pointer is +not used). For string type values `n` is the number of characters in the string `value` (not including termination), +while for `RESP_ARRAY` types the `value` is a pointer to an embedded `RESP` array and `n` is the number of elements +in that. + +You may check the integrity of a `RESP` using `redisxCheckRESP()`. Since `RESP` data is dynamically allocated, the +user is responsible for discarding them once they are no longer needed, e.g. by calling `redisxDestroyRESP()`. The +two steps may be combined to automatically discard invalid or unexpected `RESP` data in a single step by calling +`redisxCheckDestroyRESP()`. + +```c + RESP *r = ... + + // Let's say we expect 'r' to contain of an embedded RESP array of 3 elements... + int status = redisxCheckDestroyRESP(r, RESP_ARRAY, 3); + if (status != X_SUCCESS) { + // Oops, 'r' was either NULL, or does not contain a RESP array with 3 elements... + ... + } + else { + // Process the expected response... + ... + redisxDestroyRESP(r); + } +``` + +Before destroying a RESP structure, the caller may want to de-reference values within it if they are to be used +as is (without making copies), e.g.: + + +```c + RESP *r = ... + char *stringValue = NULL; // to be extracted from 'r' + + // Let's say we expect 'r' to contain of a simple string response (of whatever length) + int status = redisxCheckDestroyRESP(r, RESP_SIMPLE_STRING, 0); + if (status != X_SUCCESS) { + // Oops, 'r' was either NULL, or it was not a simple string type + ... + } + else { + // Set 'stringValue' and dereference the value field in the RESP so it's not + // destroyed with the RESP itself. + stringValue = r->value; + r->value = NULL; + + redisxDestroyRESP(r); // The 'stringValue' is still a valid pointer after! + } +``` + + +### Interactive transactions + +The simplest wat for running a few Redis queries is to do it in interactive mode: + +```c + Redis *redis = ... + RESP *resp; + int status; + + // Send "HGET my_table my_key" request + resp = redisxRequest(redis, "HGET", "my_table", "my_key", NULL, &status); + + // Check return status... + if (status != X_SUCCESS) { + // Oops something went wrong... + ... + } + ... +``` + +The `redisxRequest()` sends a command with up to three arguments. If the command takes fewer than 3 parameters, then +the remaining ones must be set to `NULL`. This function thus offers a simple interface for running most basic +sequential queries. In cases where 3 parameters are nut sufficient, you may use `redisxArrayRequest()` instead, e.g.: + +```c + ... + char *args[] = { "my_table", "my_key" }; // parameters as an array... + + // Send "HGET my_table my_key" request with an array of 2 parameters... + resp = redisxRequest(redis, "HGET", args, NULL, 2, &status); + ... + +``` + +The 4th argument in the list is an optional `int[]` array defining the individual string lengths of the parameters (if +need be, or else readily available). Here, we used `NULL` instead, which will use `strlen()` on each supplied +string-terminated parameter to determine its length automatically. Specifying the length may be necessary if the +individual parameters are not 0-terminated strings, or else substrings from a continuing string are to be used as +the parameter value. + +In interactive mode, each request is sent to the Redis server, and the response is collected before the call returns +with that response (or `NULL` if there was an error). + + +### Pipelined transactions + +Depending on round-trip times over the network, interactive queries may be suitable for running yp to a few hundred +(or a few thousand) queries per second. For higher throughput (up to millions Redis transactions per second) you may +need to access the Redis database in pipelined mode. + +In pipeline mode, requests are sent to the Redis server in quick succession without waiting for responses to return +for each one individually. Responses are then processed by a designated callback function in the background. + +```c + // Your own function to process responses to pipelined requests... + void my_resp_processor(RESP *r) { + // Do what you need to do with the asynchronous responses + // that come from Redis to bulk requests + ... + } +``` + +Before sending the requests, the user first needs to specify the function to process the responses, e.g.: + +```c + Redis *redis = ... + + redisxSetPipelineConsumer(redis, my_resp_processor); +``` + +Request are sent via the `redisxSendRequestAsync()` and `redisxSendArrayRequestAsync()` functions. Note, the `Async` +naming, which indicates the asynchronous nature of this calls -- and which also suggests that these should be called +with the approrpiate mutex locked to prevent concurrency issues. + +```c + Redis *redis = ... + + // We'll use a dedicated pipeline connection for asynchronous requests + // This way, interactive requests can still be sent independently on the interactive + // channel independently, if need be. + RedisClient *pipe = redisxGetClient(redis, PIPELINE_CHANNEL); + + // Check that the client is valid... + if (pipe == NULL) { + // Abort: we do not appear to have an active pipeline connection... + return; + } + + // Get exclusive access to the pipeline channel, so no other thread may send + // other requests concurrently... + redisxLockEnabled(pipe); + + // ------------------------------------------------------------------------- + // Submit a whole bunch of asynchronous requests, e.g. from a loop... + for (...) { + int status = redisxSendRequestAsync(pipe, ...); + if (status != X_SUCCESS) { + // Oops, that did not go through... + ... + } + else { + // We probably want to keep a record of what was requested and in what order + // so our processing function can make sense of the reponses as they arrive + // (in the same order...) + ... + } + } + // ------------------------------------------------------------------------- + + // Release the exclusive lock on the pipeline channel, so + // other threads may use it now that we sent off our requests... + redisxUnlockClient(pipe); +``` + +----------------------------------------------------------------------------- + + +## Atomic execution blocks and LUA scripts + + - [Execution blocks](#execution-blocks) + - [LUA script loading and execution](#lua-script-loading-and-execution) + + +### Execution blocks + +```c + Redis *redis = ...; + RESP *result; + + // Obtain the client on which to execute the block, e.g. the INTERACTIVE_CHANNEL + RedisClient *cl = redisxGetClient(redis, INTERACTIVE_CHANNEL); + + int status = redisxLockEnabled(cl); + if (status != X_SUCCESS) { + // Abort: we don't have exclusive access to the client + return; + } + + // ------------------------------------------------------------------------- + // Start an atomic execution block + redisxStartBlockAsync(cl); + + // Send a number of Async requests + redisxSendRequestAsync(cl, ...); + ... + + // Execute the block of commands above atomically, and get the resulting RESP + result = redisxExecBlockAsync(cl); + // ------------------------------------------------------------------------- + + // Release exlusive access to the client + redisxUnlockClient(cl); + + // Inspect the RESP, etc... + ... +``` + + +### LUA script loading and execution + +```c + Redis *redis = ... + char *script = ... // The LUA script as a 0-terminated string. + char *scriptSHA1 = NULL; // We'll store the SHA1 sum of the script here + + // Load the script onto the Redis server + int status = redixLoadScript(redis, script, &scriptSHA); + if(status != X_SUCCESS) { + // Oops, something went wrong... + ... + } +``` + +```c + Redis *redis = ... + int status; + + // Execute the script, with one redis key argument (and no parameters)... + RESP *r = redisxRequest("EVALSHA", SHA1, "1", "my-redis-key-argument", &status); + + // Check status and inspect RESP + ... +``` + +Clearly, if you have additional Redis key arguments and/or parameters to pass to the script, you'll have to use +`redisxArrayRequest()`, instead. + +----------------------------------------------------------------------------- + + +## Accessing key / value data + + - [Getting and setting keyed values](#getting-and-setting-keyed-values) + - [Listing and scanning](#listing-and-scanning) + + +### Getting and setting keyed values + +Key/value pairs are the bread and butter of Redis. They come in two variaties There are top-level key-value pairs, and +there are key-value pairs organized into hash tables, where the table name is a top-level key, but the fields in the +table are not. The RedisX library offers a unified approach for dealing with key/value pairs, whether they are top +level or hash-tables. Simply, a table name `NULL` is used to refer to top-level keys. + +Retrieving individual keyed values is simple: + +```c + Redis *redis = ...; + int status; // Variable in which we'll report error status. + + // Get the "property" field from the "system:subsystem" hash table + RESP *resp = redisxGetValue(redis, "system:subsystem", "property", &status); + if (status != X_SUCCESS) { + // Oops something went wrong. + ... + } + + // Check and process resp + ... + + // Destroy resp + redisxDestroyRESP(resp); +``` + +The same goes for top-level keyed values, using `NULL` for the hash table name: + +```c + // Get value for top-level key (not stored in hash table!) + RESP *resp = redisxGetValue(redis, NULL, "my-key", &status); +``` + +The reason the return value is a `RESP` pointer, rather than a string is twofold: (1) because it lets you process possible +error responses from Redis also, and (2) because it lets you deal with unterminated string values, such as binary sequences +of known length. + +In turn, setting values is also straightforward: + +```c + Redis *redis = ...; + + // Set the "property" field in the "system:subsystem" hash table to -2.5 + // using the interactive client connection. + int status = redisxSetValue(redis, "system:subsystem", "property", "-2.5", FALSE); + if (status != X_SUCCESS) { + // Oops something went wrong. + ... + } +``` + +It's worth noting here, that values in Redis are always represented as 'strings', hence non-string data, such as +floating-point values, must be converted to strings first. Additionally, the `redisxSetValue()` function works with +0-terminated string values only, but Redis may also store unterminated byte sequences of known length also. If you +find that you need to store an unterminated string (such as a binary sequence) as a value, you may just use the +lower-level `redisxArrayRequest()` instead to process a Redis `GET` or `HGET` command with explicit byte-length +specifications. + +In the above example we have set the value using the interactive client to Redis, which means that the call will +return only after confirmation is received from the server. As such, a subsequent `redisxGetValue()` of the same +table/key will be guaranteed to return the updated value always. However, we could have set the new value +asynchronously over the pipeline connection (by using `TRUE` as the last argument). In that case, the call will return +as soon as the request was sent to Redis (but not confirmed, not possibly transmitted yet!). As such a subsequent +`redisxGetValue()` on the same key/value field may race the request in transit, and may return the previous value on +occasion. So, it's important to remember that while pipelining can make setting multiple Redis fields very efficient, +we have to be careful about retrieving the same values afterwards from the same program thread. (Arguably, however, +there should never be a need to query values we set ourselves, since we readily know what they are.) + +Finally, if you want to set values for multiple fields in a Redis hash table atomically, you may use +`redisxMultiSet()`, which provides a high-level interface to the Redis `HMSET` command. + + +### Listing and Scanning + +The functions `redisxGetKeys()` and `redisxGetTable()` allow to return the set of Redis keywords or all key/value +pairs in a table atomically. However, these commands can be computationally expensive for large tables and/or many +top-level keywords, which means that the Redis server may block for undesirably long times while the result is +computed. + +This is where scanning offers a less selfish (hence much preferred) alternative. Rather than returning all the keys +or key/value pairs contained in a table atomically at once, it allows to do it bit by bit with byte-sized individual +transactions that are guaranteed to not block the Redis server long, so it may remain responsive to other queries +also. For the caller the result is the same, the only difference being that the result is computed via a series of +quick Redis queries rather than with one potentially very expensive query. + +For example to retrieve all top-level Redis keys, sorted alphabetically, using the scanning approach, you may write +something like: + +```c + Redis *redis = ... + + int nMatches; // We'll return the number of matching Redis keys here... + int status; // We'll return the error status here... + + // Return all redis keywords starting with "system:" + char **keys = redisxScanKeys(redis, "system:*", &n, &status); + if (status != X_SUCCESS) { + // Oops something went wrong... + ... + } + + // Use 'keys' as appropriate, possibly de-referencing values we want to + // retain in other persistent data structures... + ... + + // Once done using the 'keys' array, we should destroy it + redisxDestroyKeys(keys, nMatches); +``` + +Similarly, to retrieve a set of keywords from a table, matching a glob pattern: + +```c + ... + + // Scan all key/value pairs in hash table "system:subsystem" + RedisEntry *entries = redisxScanTable(redis, "system:subsystem", "*", &nMatches, &status); + if (status != X_SUCCESS) { + // Oops something went wrong. + ... + } + + // Use 'entries' as appropriate, possibly de-referencing values we want to + // retain in other persistent data structures... + ... + + // Once done using the 'keys' array, we should destroy it + redisxDEstroyEntries(entries, nMatches); +``` + +Finally, you may use `redisxSetScanCount()` to tune just how many results should individial scan queries return. +Please refer to the Redis documentation on the behavior of the `SCAN` and `HSCAN` commands to learn more. + +----------------------------------------------------------------------------- + + +## Publish/subscribe (PUB/SUB) support + + - [Broadcasting messages](#broadcasting-messages) + - [Subscriptions](#subscriptions) + + +### Broadcasting messages + +```c + Redis *redis = ... + + // publish a message to the "hello_channel" subscribers. + int status = redisxPublish(redis, "hello_channel", "Hello world!", 0); +``` + +The last argument is an optional string length, if readily available, or if sending a substring only (or a string that +is not 0-terminated). If zero is used, as in the example above, it will automatically determine the length of the +0-terminated string message using `strlen()`. + +Alternatively, you may use the `redisxPublishAsync()` instead if you want to publish on a subscription client to which +you have already have exlusive access (e.g. after an appropriate `redisxLockEnabled()` call). + + +### Subscriptions + +Subscriptions work conceptually similarly to pipelined requests. To process incoming messages you need to first +specify one or more `RedisSubscriberCall` functions, which will process PUB/SUB notifications automatically, in the +background, as soon as they are received. Each `RedisSubscriberCall` can pre-filter the channels for which it receives +notifications, by defining a channel stem. This way, the given processor function won't even be invoked if a +notification on a completely different channel arrives. Still, each `RedisSubscriberCall` implementation should +further check the notifying channel name as appropriate to ensure that it is in fact qualified to deal with a given +message. + +Here is an example `RedisSubscriberCall` implementation to process messages whose channel names start with +`"event:"`: + +```c + void my_event_processor(const char *pattern, const char *channel, const char *msg, long len) { + // We'll print the message onto the console + printf("Incoming message on channel %s: %s\n", channel, msg == NULL ? "" : msg); + } +``` + +There are some basic rules (best practices) for message processing. They should be fast, and never block for extended +periods. If extensive processing is required, or may need to wait extensively for some resource or mutex locking, then +its best that the processing function simply places the incoming message onto a queue, and let a separate background +thread to the heavy lifting without holding up the subsription processing of other callback routines. + +Also, it is important that the call should never attempt to modify or call `free()` on the supplied string arguments, +since that would interfere with other subscrivber calls. + +Once the function is defined, you can activate it via: + +```c + Redis *redis = ... + + int status = redisxAddSubscriber(redis, "event:", my_event_processor); + if (status != X_SUCCESS) { + // Oops, something went wrong... + ... + } +``` + +Once the processing function is registered, we can start subsribing to specific channels and/or channel patterns (see +the Redis `SUBSCRIBE` and `PSUBSCRIBE` commands for details). + +```c + Redis *redis = ... + + // We subscribe to all channels that beging with "event:"... + int status = redisxSubscribe(redis, "event:*"); + if (status != X_SUCCESS) { + // Oops, something went wrong... + ... + } +``` + +Now, we are capturing and processing all messages published to channels whose name begins with `"event:"`, using our +custom `my_event_processor` function. + +To end the subscription, we trace back the same steps in reverse oder, calling `redisxUnsubscribe()` first to stop +the delivery of further messages to the subscription channel or pattern, and then removing the `my_event_procesor` +subscriber function as appropriate (provided no other subscription needs it) via `redisxRemoveSubscriber()`. + + +----------------------------------------------------------------------------- + + +## Implementing further Redis commands + +----------------------------------------------------------------------------- + + +## Error handling + +Error handling of RedisX is an extension of that of __xchange__, with further error codes defined in `redisx.h`. +The RedisX functions that return an error status (either directly, or into the integer designated by a pointer +argument), can be inspected by `redisxErrorDescription()`, e.g.: + +```c + Redis *redis ... + int status = redisxSetValue(...); + if (status != X_SUCCESS) { + // Ooops, something went wrong... + fprintf(stderr, "WARNING! set value: %s", redisErrorDescription(status)); + ... + } +``` + + +----------------------------------------------------------------------------- + + +## Debug support + +The __xchange__ library provides two macros: `xvprintf()` and `xdprintf()`, for printing verbose and debug messages +to `stderr`. Both work just like `printf()`, but they are conditional on verbosity being enabled via +`redisxSetVerbose(boolean)` and the global variable `xDebug` being `TRUE` (non-zero), respectively. Applications using +__RedisX__ may use these macros to produce their own verbose and/or debugging outputs conditional on the same global +settings. + +You can also turn debug messages by defining the `DEBUG` constant for the compiler, e.g. by adding `-DDEBUG` to +`CFLAGS` prior to calling `make`. + +----------------------------------------------------------------------------- + + +## Future plans + +Some obvious ways the library could evolve and grow in the not too distant future: + + - Automated regression testing and coverage tracking. + - Support for the [RESP3](https://github.com/antirez/RESP3/blob/master/spec.md) standard and Redis `HELLO`. + - Support for Redis sentinel, high-availability server configurations. + - TLS support (perhaps...) + - Add more high-level redis commands, e.g. for lists, streams, etc. + - Improved debug capabilities (e.g. with built-in error traces) + - Improved error handling (e.g. by consistently setting `errno` beyond just the __RedisX__ error status). + +If you have an idea for a must have feature, please let me (Attila) know. Pull requests, for new features or fixes to +existing ones are especially welcome! + + diff --git a/resources/android-chrome-192x192.png b/resources/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..fca8ad666038c3541812ad7a371a905aec7c3e91 GIT binary patch literal 27463 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 k0PzHwK+_;ePXmbX>u0;`OCH5gjvk}I%{Rgg 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 z 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¨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 literal 0 HcmV?d00001 diff --git a/resources/favicon-32x32.png b/resources/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..a5941eb3aa871dc663ce55a7ecbf188716f2ee69 GIT binary patch literal 2203 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 literal 0 HcmV?d00001 diff --git a/resources/favicon.ico b/resources/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..cba92a6d38b06c6de96a3b82587a453d830154eb GIT binary patch literal 15406 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 literal 0 HcmV?d00001 diff --git a/resources/smithsonian-logo.png b/resources/smithsonian-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1f5dcbf82e5e7e9bdd3fdcc6461a1a1065c73a11 GIT binary patch literal 13216 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 HF%0@&mt3C9 literal 0 HcmV?d00001