1 /**
2  *
3  * @file hoel.h
4  * @brief Hoel database abstraction library
5  *
6  * hoel.h: structures and functions declarations
7  *
8  * Copyright 2015-2019 Nicolas Mora <mail@babelouest.org>
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public License
12  * as published by the Free Software Foundation;
13  * version 2.1 of the License.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU GENERAL PUBLIC LICENSE for more details.
19  *
20  * You should have received a copy of the GNU General Public
21  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24 
25 #ifndef __HOEL_H__
26 #define __HOEL_H__
27 
28 #ifdef __cplusplus
29 extern "C"
30 {
31 #endif
32 
33 #include "hoel-cfg.h"
34 
35 #include <jansson.h>
36 
37 #ifndef __USE_XOPEN
38   #define __USE_XOPEN
39 #endif
40 #include <time.h>
41 #include <pthread.h>
42 
43 /** Angharad libraries **/
44 #include <yder.h>
45 #include <orcania.h>
46 
47 /**
48  * @defgroup const Constants
49  * @{
50  */
51 
52 #define HOEL_DB_TYPE_SQLITE  0
53 #define HOEL_DB_TYPE_MARIADB 1
54 #define HOEL_DB_TYPE_PGSQL   2
55 
56 #define HOEL_COL_TYPE_INT    0
57 #define HOEL_COL_TYPE_DOUBLE 1
58 #define HOEL_COL_TYPE_TEXT   2
59 #define HOEL_COL_TYPE_DATE   3
60 #define HOEL_COL_TYPE_BLOB   4
61 #define HOEL_COL_TYPE_BOOL   5
62 #define HOEL_COL_TYPE_NULL   5
63 
64 #define H_OK                0  /* No error */
65 #define H_ERROR             1  /* Generic error */
66 #define H_ERROR_PARAMS      2  /* Error in input parameters */
67 #define H_ERROR_CONNECTION  3  /* Error in database connection */
68 #define H_ERROR_QUERY       4  /* Error executing query */
69 #define H_ERROR_MEMORY      99 /* Error allocating memory */
70 
71 #define H_OPTION_NONE   0x0000 /* Nothing whatsoever */
72 #define H_OPTION_SELECT 0x0001 /* Execute a SELECT statement */
73 #define H_OPTION_EXEC   0x0010 /* Execute an INSERT, UPDATE or DELETE statement */
74 
75 /**
76  * @}
77  */
78 
79 /**
80  * @defgroup struct struct _h_data
81  * @{
82  */
83 
84 /**
85  * handle container
86  */
87 struct _h_connection {
88   int type;
89   void * connection;
90 };
91 
92 /**
93  * sql value integer type
94  */
95 struct _h_type_int {
96   long long int value;
97 };
98 
99 /**
100  * sql value double type
101  */
102 struct _h_type_double {
103   double value;
104 };
105 
106 /**
107  * sql value date/time type
108  */
109 struct _h_type_datetime {
110   struct tm value;
111 };
112 
113 /**
114  * sql value string type
115  */
116 struct _h_type_text {
117   size_t length;
118   char * value;
119 };
120 
121 /**
122  * sql value blob type
123  */
124 struct _h_type_blob {
125   size_t length;
126   void * value;
127 };
128 
129 /**
130  * sql data container
131  */
132 struct _h_data {
133   int    type;
134   void * t_data;
135 };
136 
137 /**
138  * sql result structure
139  */
140 struct _h_result {
141   unsigned int      nb_rows;
142   unsigned int      nb_columns;
143   struct _h_data ** data;
144 };
145 
146 /**
147  * @}
148  */
149 
150 /**
151  * @defgroup init Initialize and cosing connection functions
152  * @{
153  */
154 
155 /**
156  * Close a database connection
157  * @param conn the connection to the database
158  * @return H_OK on success
159  */
160 int h_close_db(struct _h_connection * conn);
161 
162 /**
163  * @}
164  */
165 
166 /**
167  * @defgroup memory Memory management functions
168  * @{
169  */
170 
171 /**
172  * free data allocated by hoel functions
173  * @param data the data to free
174  */
175 void h_free(void * data);
176 
177 /**
178  * @}
179  */
180 
181 /**
182  * @defgroup escape Escape string functions
183  * @{
184  */
185 
186 /**
187  * h_escape_string
188  * Escapes a string
189  * @param conn the connection to the database
190  * @param unsafe the string to escape
191  * @return a heap-allocated string
192  * returned value must be h_free'd after use
193  */
194 char * h_escape_string(const struct _h_connection * conn, const char * unsafe);
195 
196 /**
197  * h_escape_string_with_quotes
198  * Escapes a string and returns it ready to be inserted in the query
199  * @param conn the connection to the database
200  * @param unsafe the string to escape
201  * @return a heap-allocated string
202  * returned value must be h_h_free'd after use
203  */
204 char * h_escape_string_with_quotes(const struct _h_connection * conn, const char * unsafe);
205 
206 /**
207  * @}
208  */
209 
210 /**
211  * @defgroup h_result _h_result SQL query management functions
212  * SQL query management for struct _h_result format
213  * @{
214  */
215 
216 /**
217  * h_execute_query
218  * Execute a query, set the result structure with the returned values if available
219  * if result is NULL, the query is executed but no value will be returned
220  * @param conn the connection to the database
221  * @param query the SQL query to execute
222  * @param result the result structure to fill the result data
223  * @param options option to pass to the database engine
224  * options available
225  * H_OPTION_NONE (0): no option
226  * H_OPTION_SELECT: Execute a prepare statement (sqlite only)
227  * H_OPTION_EXEC: Execute an exec statement (sqlite only)
228  * @return H_OK on success
229  */
230 int h_execute_query(const struct _h_connection * conn, const char * query, struct _h_result * result, int options);
231 
232 /**
233  * h_query_insert
234  * Execute an insert query
235  * @param conn the connection to the database
236  * @param query the SQL query to execute
237  * @return H_OK on success
238  */
239 int h_query_insert(const struct _h_connection * conn, const char * query);
240 
241 /**
242  * h_query_last_insert_id
243  * return the id of the last inserted value
244  * @param conn the connection to the database
245  * @return a pointer to `struct _h_data *` on success, NULL otherwise.
246  */
247 struct _h_data * h_query_last_insert_id(const struct _h_connection * conn);
248 
249 /**
250  * h_query_update
251  * Execute an update query
252  * @param conn the connection to the database
253  * @param query the SQL query to execute
254  * @return H_OK on success
255  */
256 int h_query_update(const struct _h_connection * conn, const char * query);
257 
258 /**
259  * h_query_delete
260  * Execute an delete query
261  * @param conn the connection to the database
262  * @param query the SQL query to execute
263  * @return H_OK on success
264  */
265 int h_query_delete(const struct _h_connection * conn, const char * query);
266 
267 /**
268  * h_query_select
269  * Execute a select query, set the result structure with the returned values
270  * @param conn the connection to the database
271  * @param query the SQL query to execute
272  * @param result the result structure to fill the result data
273  * @return H_OK on success
274  */
275 int h_query_select(const struct _h_connection * conn, const char * query, struct _h_result * result);
276 
277 /**
278  * @}
279  */
280 
281 /**
282  * @defgroup json JSON SQL query management functions
283  * SQL query management for JSON format
284  * @{
285  */
286 
287 /**
288  * h_execute_query_json
289  * Execute a query, set the returned values in the json result
290  * @param conn the connection to the database
291  * @param query the SQL query to execute
292  * @param j_result a json_t * reference that will be allocated and filled with the result
293  * if the query succeeds and is a SELECT query
294  * @return H_OK on success
295  */
296 int h_execute_query_json(const struct _h_connection * conn, const char * query, json_t ** j_result);
297 
298 /**
299  * h_query_select_json
300  * Execute a select query, set the returned values in the json results
301  * @param conn the connection to the database
302  * @param query the SQL query to execute
303  * @param j_result a json_t * reference that will be allocated and filled with the result if the query succeeds
304  * @return H_OK on success
305  */
306 int h_query_select_json(const struct _h_connection * conn, const char * query, json_t ** j_result);
307 
308 /**
309  * json queries
310  * The following functions run a sql query based on a json_t * object for input parameters
311  * The input parameter is called j_query
312  * If the j_query is well-formed, the query is executed and if available and specified, the result is stored into the j_result object. j_result must be decref'd after use
313  * Also, the sql query generated is stored into generated_query if specified, generated_query must be h_free'd after use
314  * The query execution result is returned by the function
315  *
316  * A j_query has the following form
317  * {
318  *   "table": "table_name"             // String, mandatory, the table name where the query is executed
319  *   "columns": ["col1", "col2"]       // Array of strings, available for h_select, optional. If not specified,will be used
320  *   "order_by": "col_name [asc|desc]" // String, available for h_select, specify the order by clause, optional
321  *   "limit": integer_value            // Integer, available for h_select, specify the limit value, optional
322  *   "offset"                          // Integer, available for h_select, specify the limit value, optional but available only if limit is set
323  *   "values": [{                      // json object or json array of json objects, available for h_insert, mandatory, specify the values to update
324  *     "col1": "value1",               // Generates col1='value1' for an update query
325  *     "col2": value_integer,          // Generates col2=value_integer for an update query
326  *     "col3", "value3",               // Generates col3='value3' for an update query
327  *     "col4", null                    // Generates col4=NULL for an update query
328  *   }]
329  *   "set": {                          // json object, available for h_update, mandatory, specify the values to update
330  *     "col1": "value1",               // Generates col1='value1' for an update query
331  *     "col2": value_integer,          // Generates col2=value_integer for an update query
332  *     "col3", "value3",               // Generates col3='value3' for an update query
333  *     "col4", null                    // Generates col4=NULL for an update query
334  *   }
335  *   "where": {                        // json object, available for h_select, h_update and h_delete, mandatory, specify the where clause. All clauses are separated with an AND operator
336  *     "col1": "value1",               // Generates col1='value1'
337  *     "col2": value_integer,          // Generates col2=value_integer
338  *     "col3": null,                   // Generates col3=NULL
339  *     "col4", {                       // Generates col4<12
340  *       "operator": "<",
341  *       "value": 12
342  *     },
343  *     "col5", {                       // Generates col5 IS NOT NULL
344  *       "operator": "NOT NULL"
345  *     },
346  *     "col6", {                       // Generates col6 LIKE '%value6%'
347  *       "operator": "raw",
348  *       "value": "LIKE '%value6%'"
349  *     }
350  *   }
351  * }
352  */
353 
354 /**
355  * h_select
356  * Execute a select query
357  * Uses a json_t * parameter for the query parameters
358  * Store the result of the query in j_result if specified. j_result must be decref'd after use
359  * @param conn the connection to the database
360  * @param j_query the query encapsulated ina JSON object to execute
361  * @param j_result a json_t * reference that will be allocated and filled with the result if the query succeeds
362  * @param generated_query a char * reference that will be allocated by the library and will contain the generated SQL query,
363  * optional, must be h_free'd after use
364  * @return H_OK on success
365  */
366 int h_select(const struct _h_connection * conn, const json_t * j_query, json_t ** j_result, char ** generated_query);
367 
368 /**
369  * h_insert
370  * Execute an insert query
371  * Uses a json_t * parameter for the query parameters
372  * @param conn the connection to the database
373  * @param j_query the query encapsulated ina JSON object to execute
374  * @param generated_query a char * reference that will be allocated by the library and will contain the generated SQL query,
375  * optional, must be h_free'd after use
376  * @return H_OK on success
377  */
378 int h_insert(const struct _h_connection * conn, const json_t * j_query, char ** generated_query);
379 
380 /**
381  * h_last_insert_id
382  * return the id of the last inserted value
383  * return a pointer to `json_t *` on success, NULL otherwise.
384  * The returned value is of type JSON_INTEGER
385  * @param conn the connection to the database
386  * @return a json_t * containing the last insert id in integer format
387  */
388 json_t * h_last_insert_id(const struct _h_connection * conn);
389 
390 /**
391  * h_update
392  * Execute an update query
393  * Uses a json_t * parameter for the query parameters
394  * @param conn the connection to the database
395  * @param j_query the query encapsulated ina JSON object to execute
396  * @param generated_query a char * reference that will be allocated by the library and will contain the generated SQL query,
397  * optional, must be h_free'd after use
398  * @return H_OK on success
399  */
400 int h_update(const struct _h_connection * conn, const json_t * j_query, char ** generated_query);
401 
402 /**
403  * h_delete
404  * Execute a delete query
405  * Uses a json_t * parameter for the query parameters
406  * @param conn the connection to the database
407  * @param j_query the query encapsulated ina JSON object to execute
408  * @param generated_query a char * reference that will be allocated by the library and will contain the generated SQL query,
409  * optional, must be h_free'd after use
410  * @return H_OK on success
411  */
412 int h_delete(const struct _h_connection * conn, const json_t * j_query, char ** generated_query);
413 
414 /**
415  * @}
416  */
417 
418 /**
419  * @defgroup h_result _h_result SQL query management functions
420  * SQL query management for struct _h_result format
421  * @{
422  */
423 
424 /**
425  * h_clean_result
426  * Free all the memory allocated by the struct _h_result
427  * @param result the result to free
428  * @return H_OK on success
429  */
430 int h_clean_result(struct _h_result * result);
431 
432 /**
433  * h_clean_data
434  * Free memory allocated by the struct _h_data
435  * @param data the data to free
436  * @return H_OK on success
437  */
438 int h_clean_data(struct _h_data * data);
439 
440 /**
441  * h_clean_data_full
442  * Free memory allocated by the struct _h_data and the struct _h_data pointer
443  * @param data the data to free
444  * @return H_OK on success
445  */
446 int h_clean_data_full(struct _h_data * data);
447 
448 /**
449  * @}
450  */
451 
452 /**
453  * @defgroup init Initialize and cosing connection functions
454  * @{
455  */
456 
457 /**
458  * h_clean_connection
459  * free memory allocated by the struct _h_connection
460  * @param conn the connection to the database
461  * @return H_OK on success
462  */
463 int h_clean_connection(struct _h_connection * conn);
464 
465 /**
466  * h_connect_sqlite
467  * Opens a database connection to a sqlite3 db file
468  * @param db_path the path to the sqlite db file
469  * @return pointer to a struct _h_connection * on sucess, NULL on error
470  */
471 struct _h_connection * h_connect_sqlite(const char * db_path);
472 
473 /**
474  * close a sqlite3 connection
475  * @param conn the connection to the database
476  */
477 void h_close_sqlite(struct _h_connection * conn);
478 
479 /**
480  * @}
481  */
482 
483 /**
484  * @defgroup escape Escape string functions
485  * @{
486  */
487 
488 /**
489  * escape a string
490  * returned value must be h_free'd after use
491  * This is an internal function, you should use h_escape_string instead
492  * @param conn the connection to the database
493  * @param unsafe the string to escape
494  * @return a heap-allocated string
495  */
496 char * h_escape_string_sqlite(const struct _h_connection * conn, const char * unsafe);
497 
498 /**
499  * escape a string
500  * returned value must be h_free'd after use
501  * This is an internal function, you should use h_escape_string_with_quotes instead
502  * @param conn the connection to the database
503  * @param unsafe the string to escape
504  * @return a heap-allocated string
505  */
506 char * h_escape_string_with_quotes_sqlite(const struct _h_connection * conn, const char * unsafe);
507 
508 /**
509  * @}
510  */
511 
512 /**
513  * @defgroup json JSON SQL query management functions
514  * SQL query management for JSON format
515  * @{
516  */
517 
518 /**
519  * Return the id of the last inserted value
520  * This is an internal function, you should use h_last_insert_id instead
521  * @param conn the connection to the database
522  * @return a long long int value
523  */
524 long long int h_last_insert_id_sqlite(const struct _h_connection * conn);
525 
526 /**
527  * h_exec_query_sqlite
528  * Execute a query on a sqlite connection
529  * This is an internal function, you should use h_exec_query instead
530  * Should not be executed by the user because all parameters are supposed to be correct
531  * No result is returned, useful for single INSERT, UPDATE or DELETE statements
532  * @param conn the connection to the database
533  * @param query the SQL query to execute
534  * @return H_OK on success
535  */
536 int h_exec_query_sqlite(const struct _h_connection * conn, const char * query);
537 
538 /**
539  * h_execute_query_json_sqlite
540  * Execute a query on a sqlite connection, set the returned values in the json result
541  * This is an internal function, you should use h_execute_query_json instead
542  * Should not be executed by the user because all parameters are supposed to be correct
543  * @param conn the connection to the database
544  * @param query the SQL query to execute
545  * @param j_result a json_t * reference that will be allocated and filled with the result
546  * @return H_OK on success
547  */
548 int h_execute_query_json_sqlite(const struct _h_connection * conn, const char * query, json_t ** j_result);
549 
550 /**
551  * @}
552  */
553 
554 /**
555  * @defgroup h_result _h_result SQL query management functions
556  * SQL query management for struct _h_result format
557  * @{
558  */
559 
560 /**
561  * h_select_query_sqlite
562  * Execute a select query on a sqlite connection, set the result structure with the returned values
563  * This is an internal function, you should use h_select_query instead
564  * Should not be executed by the user because all parameters are supposed to be correct
565  * if result is NULL, the query is executed but no value will be returned
566  * Useful for SELECT statements
567  * @param conn the connection to the database
568  * @param query the SQL query to execute
569  * @param result a _h_result that will be filled with the result
570  * return H_OK on success
571  */
572 int h_select_query_sqlite(const struct _h_connection * conn, const char * query, struct _h_result * result);
573 
574 /**
575  * @}
576  */
577 
578 /**
579  * @defgroup init Initialize and cosing connection functions
580  * @{
581  */
582 
583 /**
584  * h_connect_mariadb
585  * Opens a database connection to a mariadb server
586  * @param host the hostname of the database server
587  * @param user the username to connect to the database
588  * @param passwd the password to connect to the database
589  * @param db the database name
590  * @param port the TCP port number for the database connection, 0 means system default
591  * @param unix_socket a UNIX socket to use for the connection, optional
592  * @return pointer to a struct _h_connection * on success, NULL on error
593  */
594 struct _h_connection * h_connect_mariadb(const char * host, const char * user, const char * passwd, const char * db, const unsigned int port, const char * unix_socket);
595 
596 /**
597  * close connection to database
598  */
599 void h_close_mariadb(struct _h_connection * conn);
600 
601 /**
602  * @}
603  */
604 
605 /**
606  * @defgroup escape Escape string functions
607  * @{
608  */
609 
610 /**
611  * escape a string
612  * This is an internal function, you should use h_escape_string instead
613  * returned value must be h_free'd after use
614  * @param conn the connection to the database
615  * @param unsafe the string to escape
616  * @return a heap-allocated string
617  */
618 char * h_escape_string_mariadb(const struct _h_connection * conn, const char * unsafe);
619 
620 /**
621  * escape a string
622  * This is an internal function, you should use h_escape_string_with_quotes instead
623  * returned value must be h_free'd after use
624  * @param conn the connection to the database
625  * @param unsafe the string to escape
626  * @return a heap-allocated string
627  */
628 char * h_escape_string_with_quotes_mariadb(const struct _h_connection * conn, const char * unsafe);
629 
630 /**
631  * @}
632  */
633 
634 /**
635  * @defgroup json JSON SQL query management functions
636  * SQL query management for JSON format
637  * @{
638  */
639 
640 /**
641  * Return the id of the last inserted value
642  * This is an internal function, you should use h_last_insert_id instead
643  * @param conn the connection to the database
644  * @return a long long int value
645  */
646 long long int h_last_insert_id_mariadb(const struct _h_connection * conn);
647 
648 /**
649  * Execute a query on a mariadb connection, set the returned values in the json result
650  * This is an internal function, you should use h_execute_query_json instead
651  * Should not be executed by the user because all parameters are supposed to be correct
652  * @param conn the connection to the database
653  * @param query the SQL query to execute
654  * @param j_result a json_t * reference that will be allocated and filled with the result
655  * @return H_OK on success
656  */
657 int h_execute_query_json_mariadb(const struct _h_connection * conn, const char * query, json_t ** j_result);
658 
659 /**
660  * @}
661  */
662 
663 /**
664  * @defgroup h_result _h_result SQL query management functions
665  * SQL query management for struct _h_result format
666  * @{
667  */
668 
669 /**
670  * h_execute_query_mariadb
671  * Execute a select query on a mariadb connection, set the result structure with the returned values
672  * This is an internal function, you should use h_select_query instead
673  * Should not be executed by the user because all parameters are supposed to be correct
674  * if result is NULL, the query is executed but no value will be returned
675  * Useful for SELECT statements
676  * @param conn the connection to the database
677  * @param query the SQL query to execute
678  * @param result a _h_result that will be filled with the result
679  * @return H_OK on success
680  */
681 int h_execute_query_mariadb(const struct _h_connection * conn, const char * query, struct _h_result * result);
682 
683 /**
684  * h_get_mariadb_value
685  * convert value into a struct _h_data * depening on the m_type given
686  * This is an internal function, you should not use it
687  * returned value must be h_free'd with h_clean_data_full after use
688  * @param value the value to convert
689  * @param length the length of the value
690  * @param m_type the data type
691  * @return a _h_data * contaning the converted value
692  */
693 struct _h_data * h_get_mariadb_value(const char * value, const unsigned long length, const int m_type);
694 
695 /**
696  * @}
697  */
698 
699 /**
700  * @defgroup init Initialize and cosing connection functions
701  * @{
702  */
703 
704 /**
705  * h_connect_pgsql
706  * Opens a database connection to a PostgreSQL server
707  * @param conninfo the connection info to connect to the pgsql database
708  * @return pointer to a struct _h_connection * on sucess, NULL on error
709  */
710 struct _h_connection * h_connect_pgsql(const char * conninfo);
711 
712 /**
713  * close a pgsql connection
714  * @param conn the connection to the database
715  */
716 void h_close_pgsql(struct _h_connection * conn);
717 
718 /**
719  * @}
720  */
721 
722 /**
723  * @defgroup escape Escape string functions
724  * @{
725  */
726 
727 /**
728  * escape a string
729  * This is an internal function, you should use h_escape_string instead
730  * returned value must be h_free'd after use
731  * @param conn the connection to the database
732  * @param unsafe the string to escape
733  * @return a heap-allocated string
734  */
735 char * h_escape_string_pgsql(const struct _h_connection * conn, const char * unsafe);
736 
737 /**
738  * escape a string
739  * This is an internal function, you should use h_escape_string_with_quotes instead
740  * returned value must be h_free'd after use
741  * @param conn the connection to the database
742  * @param unsafe the string to escape
743  * @return a heap-allocated string
744  */
745 char * h_escape_string_with_quotes_pgsql(const struct _h_connection * conn, const char * unsafe);
746 
747 /**
748  * @}
749  */
750 
751 /**
752  * @defgroup json JSON SQL query management functions
753  * SQL query management for JSON format
754  * @{
755  */
756 
757 /**
758  * h_execute_query_json_pgsql
759  * Execute a query on a pgsql connection, set the returned values in the json results
760  * This is an internal function, you should use h_execute_query_json instead
761  * Should not be executed by the user because all parameters are supposed to be correct
762  * @param conn the connection to the database
763  * @param query the SQL query to execute
764  * @param j_result a json_t * reference that will be allocated and filled with the result
765  * @return H_OK on success
766  */
767 int h_execute_query_json_pgsql(const struct _h_connection * conn, const char * query, json_t ** j_result);
768 
769 /**
770  * Return the id of the last inserted value
771  * This is an internal function, you should use h_last_insert_id instead
772  * @param conn the connection to the database
773  * @return a long long int value
774  */
775 long long int h_last_insert_id_pgsql(const struct _h_connection * conn);
776 
777 /**
778  * @}
779  */
780 
781 /**
782  * @defgroup h_result _h_result SQL query management functions
783  * SQL query management for struct _h_result format
784  * @{
785  */
786 
787 /**
788  * h_execute_query_pgsql
789  * Execute a select query on a pgsql connection, set the result structure with the returned values
790  * This is an internal function, you should use h_select_query instead
791  * Should not be executed by the user because all parameters are supposed to be correct
792  * if result is NULL, the query is executed but no value will be returned
793  * Useful for SELECT statements
794  * @param conn the connection to the database
795  * @param query the SQL query to execute
796  * @param result a _h_result that will be filled with the result
797  * return H_OK on success
798  */
799 int h_execute_query_pgsql(const struct _h_connection * conn, const char * query, struct _h_result * result);
800 
801 /**
802  * @}
803  */
804 
805 #ifdef __cplusplus
806 }
807 #endif
808 
809 #endif /* __HOEL_H__ */
810