Wiki page lists.md changed with summary [created] by Paul

This commit is contained in:
Paul 2017-11-09 03:26:18 -08:00 committed by apache
parent 39c6643699
commit 4d03ebc185
2 changed files with 647 additions and 119 deletions

View File

@ -1,119 +0,0 @@
---
~~Title: Tutorial 1: Hello World~~
---
# Tutorial 1: Hello World #
This tutorial will guide you through the necessary steps to build your first "Hello World" example using the *Enlightenment Foundation Libraries* (EFL). Before continuing make sure you have read the [Setting up the Development Environment](/develop/setup/c/) guide.
There is very little code in this first tutorial so don't worry if you have little coding experience. The main goal is to build and execute an application using EFL. You will need a basic knowledge of C to get started.
## Step One: Includes ##
Using your favorite text editor, create a text file and save it as ``hello-world.c``. Type in the following:
```c
#include <Eina.h>
#include <Efl.h>
#include <Elementary.h>
```
The EFL is split into several libraries. You only need to include the ones you actually want to use. In this tutorial we are calling methods from the ``Eina`` and ``Efl`` libraries, therefore we need to include the ``Eina.h`` and ``Efl.h`` headers.
> **NOTE:**
> The ``Elementary.h`` header is special and required for the program to compile. It will be removed soon, however.
If you're not sure which libraries your program is actually using just look at the prefix of the EFL methods and macros. In this case we're using ``eina_``, ``EINA_``, ``efl_`` and ``EFL_``.
You will explore the EFL libraries in greater depth in later tutorials. In the meantime, visit the [List of EFL Libraries](list-of-efl-libraries.md) for an overview of the purpose of each one.
## Step Two: Main Function ##
Instead of the ``main()`` function marking the standard C entry point EFL uses ``efl_main()``. Type the following underneath the includes section of your program:
```c
void
efl_main(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED)
{
}
```
EFL takes care of all initialization tasks and calls your ``efl_main()`` method when everything is ready.
We will focus on the ``efl_main()`` parameters in the following tutorial. In this one we're not using them, hence the ``EINA_UNUSED`` macro. This is optional but it gets rid of warnings regarding unused parameters so it's worth having.
## Step Three: Print "Hello World" ##
Type the following between the curly brackets of ``efl_main()``:
```c
printf("Hello World!\n");
```
This is a regular C ``printf()`` which will output the "Hello World" string to the console.
## Step Four: Exiting ##
Any programs you create with EFL must always terminate by calling ``efl_exit()``. This is an important difference to the regular C ``main()``, where a program exits when it reaches the end of a method. Enter the following below your ``printf()``:
```c
efl_exit(0);
```
The parameter ``efl_exit()`` is the value your program returns to the operating system.
## Step Five: Automatic EFL setup and Shutdown ##
This final piece of "boilerplate" code should be included at the end of every EFL program. Type the following at the very end of your program as the last line:
```c
EFL_MAIN()
```
This defines the real ``main()`` method required by C programs, which deals with initialization and deinitilization tasks. It also eventually calls the ``efl_main()`` method that you defined above.
This is not mandatory but it simplifies the setup and shutdown processes considerably, so we are going to use it in this series of tutorials.
## The Complete Program ##
```c
#include <Eina.h>
#include <Efl.h>
#include <Elementary.h>
void
efl_main(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED)
{
printf("Hello World!\n");
efl_exit(0);
}
EFL_MAIN()
```
## Running the Program ##
Save the program then build it as outlined in [Setting up the Development Environment](/develop/setup/c/#Building). If you are using the ``gcc`` compiler, run:
```bash
gcc -o hello-world hello-world.c `pkg-config --cflags --libs eina efl elementary` -DEFL_EO_API_SUPPORT=1 -DEFL_BETA_API_SUPPORT=1
```
If the systems displays no errors, your program should be ready. Test it by typing:
```bash
./hello-world
```
The words ``Hello World!`` will now appear on the screen.
## Summary ##
At the end of this tutorial you have learned:
* Header files must be included for any EFL libraries you intend to use. Typically, these are ``Eina.h`` and ``Efl.h``.
* Your main method should be ``efl_main()``.
* Your EFL programs should always call ``efl_exit()`` at some stage.
* Your EFL programs should include the ``EFL_MAIN()`` macro at the end so EFL can insert its own start-up and shutdown code.
The next tutorial keeps introducing more basic concepts, and shows how to retrieve the command line parameters passed to your program.

View File

@ -0,0 +1,647 @@
{{page>index}}
-------
# Lists #
The ``Eina_List`` is a double-linked list that can store data of any type as
void pointers. It provides a set of functions to create and manipulate the
list to avoid the access to the struct's fields, similar to a self-made
double-link list.
In addition to the previous and next node and its data, the ``Eina_List``
nodes keep a reference to an accounting structure. The accounting structure is
used to improve the performance of some functions. The structure is private
and must not be modified.
In an ``Eina_List``, everything is a "list": the list itself is a list where
each node is a list as well.
Eina provides 2 list types: the classic list (``Eina_List``) and an inline
list (``Eina_Inlist``).
## Creating and Destroying a List ##
To use an ``Eina_List``:
__**1**__. Declare the list with ``NULL`` as the default value:
```c
[...]
int list()
{
// Declaration of the Eina_List with NULL as default value;
Eina_List *list = NULL;
[...]
```
__**2**__. Call the ``eina_list_append()`` function with the list and the data you
want to append as parameters.
The list must be a pointer to the first element of the list (or ``NULL``). The
function returns a pointer to the list.
```c
[...]
// Creating the first element of the list
list = eina_list_append(list, "watch");
// Adding more elements
list = eina_list_append(list, "phone");
list = eina_list_append(list, "ivi");
list = eina_list_append(list, "notebook");
[...]
```
__**3**__. When you no longer need the list, free it:
```c
[...]
// Free the Eina_List
eina_list_free(list);
return 0;
}
[...]
```
## Modifying List Content ##
### To add data to a list ###
* To add data at the end of the list, use the ``eina_list_append()`` function. To add data at the top of the list, use ``eina_list_prepend()``. The functions work in the same way, only adding the data to different places.
```c
[...]
list = eina_list_prepend(list, "set-top box");
[...]
```
* To insert data into the list after a specified data, use the ``eina_list_append_relative()`` function. As the last parameter, define the element after which the data is added. \\ \\ For example to append data after the "phone" element:
```c
[...]
list = eina_list_append_relative(list, "single-board computer", "phone");
[...]
```
* To add a new entry before a specified data, use the ``eina_list_prepend_relative()`` function. It is similar to the ``eina_list_append_relative()`` function.
```c
[...]
list = eina_list_prepend_relative(list, "ultrabook", "ivi");
[...]
```
* To append a list node to a linked list after a specified member, use the ``eina_list_append_relative_list()`` function. To prepend a list node to a linked list before a specified member, use the ``Eina_List * eina_list_prepend_relative_list()`` function.
### To set data in a list member ###
Use the ``eina_list_data_set()`` function. Pass the
"list" (node) as the first argument and the data to set as the second.
The following example also shows the usage of the ``eina_list_last()``
function, which returns the last element of an ``Eina_List``.
```c
[...]
// Setting new data for the last element
eina_list_data_set(eina_list_last(list), eina_stringshare_add("Boris"));
[...]
```
### To remove a node from the list ###
Use the ``eina_list_remove()`` function. This function removes the first
instance of the specified data from the given list.
```c
[...]
list = eina_list_remove(list, "ultrabook");
[...]
```
You can also remove a "list" (node) from a list using the
``eina_list_remove_list()`` function. Pass the list you want to delete an
element from and a 'list' (node) you want to delete.
```c
[...]
Eina_List *app_list = NULL;
Eina_List *to_remove = NULL;
// Adding some elements to the list (using stringshares)
app_list = eina_list_append(app_list, eina_stringshare_add("enna"));
app_list = eina_list_append(app_list, eina_stringshare_add("ebird"));
app_list = eina_list_append(app_list, eina_stringshare_add("calaos"));
app_list = eina_list_append(app_list, eina_stringshare_add("rage"));
app_list = eina_list_append(app_list, eina_stringshare_add("terminology"));
app_list = eina_list_append(app_list, eina_stringshare_add("enlightenment"));
app_list = eina_list_append(app_list, eina_stringshare_add("eyelight"));
app_list = eina_list_append(app_list, eina_stringshare_add("ephoto"));
// Finding the "list" to remove
to_remove = eina_list_data_find_list(list, eina_string_share_add("enlightenment"));
list = eina_list_remove_list(list, to_remove);
[...]
```
### To move elements in a list ###
You can use various function, such as ``eina_list_promote_list()`` that
promotes an element to the top of the list or ``eina_list_demote_list()`` that
puts the specified element at the end of the list. Remember that everything is
a list so the second parameter represents the "list" (node) you want to move.
Use the functions just like the ``eina_list_remove_list()`` function.
```c
[...]
list = eina_list_promote_list(list, eina_list_data_find_list(list, "ivi"));
[...]
```
### To reverse all the elements of a list ###
Use the ``eina_list_reverse()`` function. To obtain a reversed copy of the
list while keeping the initial list unchanged, use the
``eina_list_reverse_clone()`` function.
```c
[...]
Eina_List *rev_copy;
app_list = eina_list_reverse(app_list);
rev_copy = eina_list_reverse_clone(app_list);
[...]
```
### To sort a list ###
Use the ``eina_list_sort()`` function. This function takes a list which needs
to be sorted, the maximum number of elements to be sorted, and a callback
function that compares data. To sort all list elements, set the maximum number
of elements to 0.
```c
[...]
int sort_cb(const void *d1, const void *d2)
{
const char *txt = d1;
const char *txt2 = d2;
if(!txt) return(1);
if(!txt2) return(-1);
return(strcmp(txt, txt2));
}
extern Eina_List *list;
list = eina_list_sort(list, 0, sort_cb);
[...]
```
### To merge 2 list into 1 ###
Use the ``eina_list_merge()`` function. The ``eina_list_sorted_merge()``
function merges 2 sorted lists according to the ordering function that you
pass as the last argument.
```c
[...]
int sort_cb(void *d1, void *d2)
{
const char *txt = NULL;
const char *txt2 = NULL;
if(!d1) return(1);
if(!d2) return(-1);
return(strcmp((const char*)d1, (const char*)d2));
}
Eina_List *sorted1;
Eina_List *sorted2;
Eina_List *newlist;
// Insert some values and sort your lists
// Simply merge 2 lists without any process
newlist = eina_list_merge(sorted1, sorted2);
newlist = eina_list_sorted_merge(sorted1, sorted2, sort_cb);
[...]
```
### To split a list ###
Use the eina_list_split_list() function:
* The first parameter is the list to split.
* The second parameter is the "list" (element) after which the list is split.
* The last parameter is the head of the second list.
```c
[...]
// Original list (left list)
Eina_List *list = NULL;
// New list (right list)
Eina_List *other_list = NULL;
// Eina_List (element)
Eina_List *l;
list = eina_list_append(list, "super tux");
list = eina_list_append(list, "frozen bubble");
list = eina_list_append(list, "lincity-ng");
// Sorting the list (just for fun)
list = eina_list_sort(list, 0, cmp_func);
// Looking for the 'split' element
l = eina_list_search_sorted_list(list, cmp_func, "frozen bubble");
// Splitting the list
list = eina_list_split_list(list, l, &other_list);
[...]
```
### To copy a list ###
Use the ``eina_list_clone()`` function. The function copies all the elements
in the list in the exact same order.
```c
[...]
Eina_List *app_list_copy;
app_list_copy = eina_list_clone(app_list);
[...]
```
## Accessing List Data ##
### To find some data on your list ###
Use the ``eina_list_data_find()`` function. Pass the list containing your data
as the first parameter and the data you are looking for as the last one. The
function returns the found member data pointer if found, ``NULL`` otherwise.
The ``eina_list_data_find()`` function searches the list from the beginning to
the end for the first member for which the data pointer is data. If it is
found, the data is returned, otherwise ``NULL`` is returned. The function only
compares pointers, which is why using ``Eina_Stringshare`` is very useful with
lists, because it always returns the same pointer for the same string.
```c
[...]
Eina_List *app_list = NULL;
const char *res_str;
// Adding some elements to the list (using stringshares)
app_list = eina_list_append(app_list, eina_stringshare_add("enna"));
app_list = eina_list_append(app_list, eina_stringshare_add("ebird"));
app_list = eina_list_append(app_list, eina_stringshare_add("calaos"));
app_list = eina_list_append(app_list, eina_stringshare_add("rage"));
app_list = eina_list_append(app_list, eina_stringshare_add("terminology"));
app_list = eina_list_append(app_list, eina_stringshare_add("enlightenment"));
app_list = eina_list_append(app_list, eina_stringshare_add("eyelight"));
app_list = eina_list_append(app_list, eina_stringshare_add("ephoto"));
// Finding the data
res_str = eina_list_data_find(list, eina_string_share_add("enlightenment"));
if (res_str #### eina_stringshare_add("enlightenment"))
printf("Data is present");
else
printf("Data not present");
[...]
```
The above example returns "Data is present".
The ``eina_list_data_find_list()`` function does the same thing as
``eina_list_data_find()``, but returns an ``Eina_List``. For an example, see
the ``eina_list_remove_list()`` function.
You can access the data or a "list" (node) of an ``Eina_List`` using the
``eina_list_nth()`` and ``eina_list_nth_list()`` functions. The first one returns a
pointer to the data of the "n" element and the second a pointer to the "list".
To access the data of the 3rd element of an ``Eina_List``:
```c
[...]
const char *res;
Eina_List *res_lst;
res = eina_list_nth(app_list, 2);
res_lst = eina_list_nth_list(app_list, 2);
[...]
```
The ``res`` variable contains the pointer to the string "calaos". The
``res_lst`` variable is the list containing "calaos".
### To search for data in a list ###
Select your function based on whether the list is sorted or unsorted.
* To search in an unsorted list, use the ``eina_list_search_unsorted()`` function:
* The first parameter is the list.
* The second parameter is a callback function for comparison.
* The last parameter is the data you are looking for.
The ``eina_list_search_unsorted_list()`` function does the same but returns an
"Eina_List".
The following example shows 2 searches using both the
``eina_list_search_unsorted()`` and ``eina_list_search_unsorted_list()``
functions:
```c
[...]
int search_list()
{
// Declaring the list
Eina_List *list = NULL;
Eina_List *l;
// Little trick to use strcmp as Eina_Compare_Cb
Eina_Compare_Cb cmp_func = (Eina_Compare_Cb)strcmp;
void *data;
int cmp_result;
list = eina_list_append(list, "debian");
list = eina_list_append(list, "archlinux");
list = eina_list_append(list, "centos");
data = eina_list_search_unsorted(list, cmp_func, "archlinux");
l = eina_list_search_unsorted_list(list, cmp_func, "archlinux");
if (l->data != data)
{
eina_list_free(list);
return 1;
}
eina_list_free(list);
return 0;
}
[...]
```
* To search in sorted lists, use the ``eina_list_search_sorted_list()`` and ``eina_list_search_sorted()`` functions. They work similarly as the ``eina_list_search_unsorted()`` function.
### To get data from a list element ###
Use the ``eina_list_data_get()`` function. The function returns the data
contained in the given list.
The following example uses the ``eina_list_next()`` function to move through
the list in a statement.
```c
[...]
int list_data_set()
{
// Declaring the list
Eina_List *list = NULL;
// Eina_List in which to place the elements or lists
Eina_List *l;
void *list_data;
list = eina_list_append(list, eina_stringshare_add("Bertrand"));
list = eina_list_append(list, eina_stringshare_add("Cedric"));
list = eina_list_append(list, eina_stringshare_add("Nicolas"));
list = eina_list_append(list, eina_stringshare_add("Vincent"));
list = eina_list_append(list, eina_stringshare_add("Raoul"));
list = eina_list_append(list, eina_stringshare_add("Fabien"));
list = eina_list_append(list, eina_stringshare_add("Philippe"));
list = eina_list_append(list, eina_stringshare_add("billiob"));
for(l = list; l; l = eina_list_next(l))
// Printing the data returned by eina_list_data_get
printf("%s\n", (char*)eina_list_data_get(l));
EINA_LIST_FREE(list, list_data)
eina_stringshare_del(list_data);
return 0;
}
[...]
```
### To move in a list ###
Use the ``eina_list_last()``, ``eina_list_next()``, or ``eina_list_prev()``
functions to move to the last, next, or previous element in the list.
The following example scrolls backwards starting from the end of the list:
```c
[...]
for(l = eina_list_last(list); l; l = eina_list_prev(l))
printf("%s\n", (char*)eina_list_data_get(l));
[...]
```
### To count the list elements ###
Use the ``eina_list_count()`` function. The function returns the number of
items in a list.
```c
[...]
printf("List size: %d\n", eina_list_count(list));
[...]
```
### To iterate through an array ###
You can use various iterators:
* To iterate over a list from the beginning to the end, use the ``EINA_LIST_FOREACH`` macro:
* The first parameter is the list to iterate.
* The second parameter is an ``Eina_List *`` to hold the current "List" (node).
* The last parameter receives the current data during the run.
The following example prints the data of each "List" (node) of the list:
```c
[...]
Eina_List *list = NULL;
Eina_List *l;
void *list_data;
list = eina_list_append(list, "ls");
list = eina_list_append(list, "top");
list = eina_list_append(list, "rmdir");
list = eina_list_append(list, "uname");
EINA_LIST_FOREACH(list, l, list_data)
printf("%s\n", (char*)list_data);
eina_list_free(list);
[...]
```
* To iterate from the last element to the first, use the ``EINA_LIST_REVERSE_FOREACH`` macro. It works similarly as ``EINA_LIST_FOREACH()``.
* To iterate over a list from the beginning to the end, you can also use the
``EINA_LIST_FOREACH_SAFE`` macro. It is called safe, because it stores the next "List" (node), so you can safely remove the current "List" (node) and continue the iteration.
```c
[...]
Eina_List *list;
Eina_List *l;
Eina_List *l_next;
char *data;
list = eina_list_append(list, "enlightenment");
list = eina_list_append(list, "enlightenment");
list = eina_list_append(list, "enlightenment");
list = eina_list_append(list, "enlightenment");
// Using EINA_LIST_FOREACH_SAFE to free the elements that match "enlightenment"
EINA_LIST_FOREACH_SAFE(list, l, l_next, data)
if (strcmp(data, "enlightenment") #### 0)
{
free(data);
list = eina_list_remove_list(list, l);
}
[...]
```
* To remove each list element while having access to the node's data, use the ``EINA_LIST_FREE`` macro. Pass the list and a pointer to hold the current data.
```c
[...]
Eina_List *list;
char *data;
// List is filled
EINA_LIST_FREE(list, data)
free(data);
[...]
```
## Using an Inline List ##
The ``Eina_Inlist`` is a special data type drawn to store nodes pointers in
the same memory as data. This way the memory is less fragmented, but
operations, such as sort and count, are slower. The ``Eina_Inlist`` has its
own purpose, but if you do not understand what the purpose is, use the regular
``Eina_List`` instead.
The ``Eina_Inlist`` nodes can be part of a regular ``Eina_List``, simply added
with the ``eina_list_append()`` or ``eina_list_prepend()`` functions.
To use the inline list:
__**1**__. Define the structure of the data before creating the inline list:
```c
[...]
struct my_struct
{
EINA_INLIST;
int a, b;
};
[...]
```
The structure is composed of 2 integers, the real data, and the
``EINA_INLIST`` type which is composed of 3 pointers defining the inline list
structure:
* ``Eina_Inlist * next``: next node
* ``Eina_Inlist * prev``: previous node
* ``Eina_Inlist * last``: last node
__**2**__. To create the inlist nodes, allocate the memory and use the
``eina_inlist_append()`` function:
* The first parameter is the existing list head or NULL to create a new list. \\ \\ The following example passes NULL to create a new list.
* The second parameter is the new list node, and it must not be NULL. \\ \\ You must use the ``EINA_INLIST_GET()`` macro to get the inlist object of the datastruct.
```c
[...]
struct my_struct *d, *cur;
Eina_Inlist *list, *itr, *tmp;
d = malloc(sizeof(*d));
d->a = 1;
d->b = 10;
list = eina_inlist_append(NULL, EINA_INLIST_GET(d));
[...]
```
Repeat this operation for every new node:
```c
[...]
d = malloc(sizeof(*d));
d->a = 2;
d->b = 20;
list = eina_inlist_append(list, EINA_INLIST_GET(d));
[...]
```
__**3**__. To add data to the inline list:
* Put data at the end of the inline list with the ``eina_inlist_prepend()`` function:
```c
[...]
d = malloc(sizeof(*d));
d->a = 3;
d->b = 30;
list = eina_inlist_prepend(list, EINA_INLIST_GET(d));
[...]
```
* Add a node before or after a given node with the ``eina_inlist_prepend_relative()`` and ``eina_inlist_append_relative()`` functions. \\ \\ In both functions, the first parameter is the target list, the second is the element you want to add, and the last is the reference element to place data after (in this case). Similarly as in a regular ``Eina_List``, everything is a list, so the last parameter is an ``Eina_Inlist`` typed variable.
```c
[...]
d = malloc(sizeof(*d));
d->a = 4;
d->b = 40;
list = eina_inlist_append_relative(list, EINA_INLIST_GET(d), list);
[...]
```
__**4**__. To sort and iterate an inline list, to find and move list elements, and to perform other inline list operations, see the Inline List API.
__**5**__. When the inline list is no longer needed, destroy it by looping over the list to free each ``EINA_INLIST`` structure and the data using allocated memory. Use the ``eina_inlist_remove()`` function on each node.
In the following example, the ``EINA_INLIST_CONTAINER_GET()`` macro returns
the container object of an inlist (the ``EINA_INLIST`` of ``my_struct``), and
the list element is removed and the allocated memory of the container "object"
is freed.
```c
[...]
while (list)
{
struct my_struct *aux = EINA_INLIST_CONTAINER_GET(list, struct my_struct);
// Remove the current list element
list = eina_inlist_remove(list, list);
free(aux);
}
[...]
```
### Further Reading ###
[List API](https://build.enlightenment.org/job/nightly_efl_gcc_x86_64/lastSuccessfulBuild/artifact/doc/html/group__Eina__List__Group.html)
: Functions that provide list management.
[List Example 1](https://build.enlightenment.org/job/nightly_efl_gcc_x86_64/lastSuccessfulBuild/artifact/doc/html/eina_list_01_8c-example.html)
: Example of list usage 1.
[List Example 2](https://build.enlightenment.org/job/nightly_efl_gcc_x86_64/lastSuccessfulBuild/artifact/doc/html/eina_list_02_8c-example.html)
: Example of list usage 2.
[List Example 3](https://build.enlightenment.org/job/nightly_efl_gcc_x86_64/lastSuccessfulBuild/artifact/doc/html/eina_list_03_8c-example.html)
: Example of list usage 3.
[List Example 4](https://build.enlightenment.org/job/nightly_efl_gcc_x86_64/lastSuccessfulBuild/artifact/doc/html/eina_list_04_8c-example.html)
: Example of list usage 4.