<li><span style="font-family: Courier New,Courier,monospace">data_control_map_remove(s_info.provider, key, value, &req_id);</span> - this function is used to remove the given value held by the given key. If a key is empty after this operation, it should be removed as well. If there is no value equal to <span style="font-family: Courier New,Courier,monospace">value</span> or key equal to <span style="font-family: Courier New,Courier,monospace">key</span>, an error message should be provided. The key string is taken from the <span style="font-family: Courier New,Courier,monospace"><a href="#ui-struct-map">key_entry</a></span> widget and the value from <span style="font-family: Courier New,Courier,monospace"><a href="#ui-struct-map">new_value_entry</a></span> widget.</li>
</ul>
-<p>Note that there is one extra button in the <a href="#ui-struct-map">map view</a>. The <span style="font-family: Courier New,Courier,monospace">Keys</span> button sends a special get request using a "#GET_ALL_KEYS" key. In this case value received from the provider will contain all keys stored by the provider app.</p>
+<p id = "consumer-get-all-keys">Note that there is one extra button in the <a href="#ui-struct-map">map view</a>. The <span style="font-family: Courier New,Courier,monospace">Keys</span> button sends a special get request using a "#GET_ALL_KEYS" key. In this case value received from the provider will contain all keys stored by the provider app.</p>
<p>The above functions are invoked by click events of the <span style="font-family: Courier New,Courier,monospace">get_data_button</span>, <span style="font-family: Courier New,Courier,monospace">set_data_button</span>, <span style="font-family: Courier New,Courier,monospace">remove_data_button</span> and <span style="font-family: Courier New,Courier,monospace">add_data_button</span> buttons placed in the <a href="#ui-struct-map">map view</a>. The above functions are used to send requests to the provider app. The provider app should send a response. Based on the response type, one of the below callbacks is invoked.</p>
-<h5>Callback definitions:</h5>
+<h5 id = "consumer-callback-definitions">Callback definitions:</h5>
<pre class="prettyprint">
static void __map_get_response_cb(int request_id, data_control_h provider, char **ret_value_list, int ret_value_count, bool provider_ret, const char *error, void *user_data)
/* ... */
}
</pre>
+
+
+<h4>Eina_Hash functions</h4>
+<p>The map provider part of the application uses the <span style="font-family: Courier New,Courier,monospace">Eina_Hash</span> structure to store data. Note that every key in the hash can hold multiple values, so a simple key/value pair is not enough. Every key has an <span style="font-family: Courier New,Courier,monospace">Eina_List</span> assigned as its data. There are five functions in total that allow to interact with the hash map. All of them are invoked by a proper callback.</p>
+
+<p>The function used to add new data to the hash map. As mentioned before, if a key doesn't exist, a new key should be created:</p>
+<pre class="prettyprint">
+static int __data_map_add(int request_id, const char *key, const char *value)
+{
+ /* ... */
+
+ entry = (Eina_List *)eina_hash_find(s_info.data_map, key); /* Find an Eina_List assigned to the passed key. */
+
+ if (entry) {
+ /* If an Eina_List is found, a new value is added to it, and the Eina_Hash key is modified accordingly.
+ Note that the data added to the Eina_List is sorted so the eina_hash_list_* group of functions cannot be used. */
+ entry = eina_list_sorted_insert(entry, __data_map_item_value_comparator_cb, strdup(value));
+ /* ... */
+ } else {
+ /* If an Eina_List is not found, a new list is created. A new key is created with the new list used at its value. */
+ entry = eina_list_append(NULL, strdup(value));
+ /* ... */
+ }
+
+ return eina_list_count(entry);
+}
+</pre>
+
+<p>The function below is a special 'get' function. When 'get' request with a special <a href = "data_control_consumer_sd_mn.htm#consumer-get-all-keys">key</a> is sent from the consumer app, an array of all keys in the hash map are sent back instead of a value array:</p>
+<pre class="prettyprint">
+static char **__get_all_keys(int *values_count)
+{
+ *values_count = eina_hash_population(s_info.data_map);
+ char **ret = calloc(*values_count, sizeof(char *));
+ eina_hash_foreach(s_info.data_map, __get_all_keys_cb, (char **)ret);
+ return ret;
+}
+</pre>
+
+<p>The function used to get an array of values held by the given key:</p>
+<pre class="prettyprint">
+static char **__data_map_get(int request_id, const char *key, int *values_count)
+{
+ /* If the requested key is equal to '#GET_ALL_KEYS', return an array of all available keys. */
+ if(!__str_cmp_precise(key, GET_ALL_KEYS))
+ return __get_all_keys(values_count);
+
+ /* Find an Eina_List assigned to the given key */
+ entry = (Eina_List *)eina_hash_find(s_info.data_map, key);
+ if (!entry) {
+ *values_count = 0;
+
+ /* If no Eina_List is found, an error message is sent.
+ Note that this call will automatically set the <a href = "data_control_consumer_sd_mn.htm#consumer-callback-definitions">provider_ret</a> in the consumer's app callback to false. */
+ data_control_provider_send_error(request_id, NO_KEY_FOUND);
+ return NULL;
+ }
+
+ /* Prepare an array of strings with values assigned to the given key. */
+ *values_count = eina_list_count(entry);
+ char **ret = calloc(*values_count, sizeof(char *));
+
+ EINA_LIST_FOREACH(entry, l, item)
+ {
+ ret[index] = item;
+ index++;
+ }
+ return ret;
+}
+</pre>
+
+<p>The function used to update the value assigned to the given key:</p>
+<pre class="prettyprint">
+static Eina_Bool __data_map_set(int request_id, const char *key, const char *old, const char *new)
+{
+ /* ... */
+
+ /* Search for the value to modify. */
+ Eina_List *old_data_list = __search_value(entry, key, old);
+ /* ... */
+
+ /* Remove the found value. This is used to simplify the sorted insertion to the Eina_List. */
+ entry = eina_list_remove_list(entry, old_data_list);
+ if (!entry)
+ dlog_print(DLOG_INFO, LOG_TAG, "entry == NULL");
+
+ /* Insert the new value. */
+ entry = eina_list_sorted_insert(entry, __data_map_item_value_comparator_cb, strdup(new));
+
+ /* Modify the key. */
+ if (!eina_hash_modify(s_info.data_map, key, entry)) {
+ dlog_print(DLOG_ERROR, LOG_TAG, "Failed to modify a key value pair");
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+</pre>
+
+<p>The function used to remove the value assigned to the given key:</p>
+<pre class="prettyprint">
+static void __data_map_remove(int request_id, const char* key, const char *value)
+{
+ /* ... */
+
+ if(eina_list_count(entry) > 1) {
+ entry = eina_list_remove_list(entry, old_data_list);
+ if (!eina_hash_modify(s_info.data_map, key, entry)) {
+ dlog_print(DLOG_ERROR, LOG_TAG, "Failed to modify a key value pair");
+ return;
+ }
+
+ } else {
+ /* If akey is left empty after the value removal the key should be removed as well. */
+ if (!eina_hash_del_by_key(s_info.data_map, key)) {
+ dlog_print(DLOG_ERROR, LOG_TAG, "Failed to remove a key: %s", key);
+ return;
+ } else {
+ dlog_print(DLOG_INFO, LOG_TAG, "Key [%s] removed", key);
+ text = eina_stringshare_printf(KEY_REMOVED, key);
+ data_control_provider_send_error(request_id, text);
+ eina_stringshare_del(text);
+ }
+ }
+}
+</pre>
+
<!-- ********************************************************************************** -->
<script type="text/javascript" src="../scripts/jquery.zclip.min.js"></script>