term.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. #ifndef _LSUP_TERM_H
  2. #define _LSUP_TERM_H
  3. #include <assert.h>
  4. #include "buffer.h"
  5. #include "namespace.h"
  6. #define UUID4_URN_SIZE UUIDSTR_SIZE + 10
  7. // Some common RDF term values.
  8. #define LSUP_RDF_TYPE "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
  9. #define LSUP_RDF_TYPE_NS "rdf:type"
  10. /// Default data type for untyped literals (prefixed IRI).
  11. #define DEFAULT_DTYPE "http://www.w3.org/2001/XMLSchema#string"
  12. #define DEFAULT_DTYPE_NS "xsd:string"
  13. /** @brief URI parsing regular expression.
  14. *
  15. * Based on RFC3986 (see https://tools.ietf.org/html/rfc3986#appendix-B) and
  16. * modified for use in this application. Relevant matching groups are the
  17. * following, for a sample URI `http://example.org/123/456/?query=blah#frag`:
  18. *
  19. * #0: Full parsed URI (http://example.org/123/456/?query=blah#frag)
  20. * #1: Domain prefix (http://example.org)
  21. * #2: Protocol (http:)
  22. * #4: Authority (example.org)
  23. * #5: Path relative to domain (/123/456/?query=blah#frag)
  24. * #6: Path, excluding query and fragment (/123/456/)
  25. * #8: Query (query=blah)
  26. * #10: Fragment (frag)
  27. *
  28. * For URN-like URIs, such as `urn:s:0`, the prefix part (#1) is `urn:` and
  29. * the path (#4) is `s:0`.
  30. *
  31. * TODO Remove. Superseded by ad-hoc scanning (see static parse_ini in term.c.)
  32. */
  33. #define LSUP_URI_REGEX_STR \
  34. "^(([^:/?#]+:)?(//([^/?#]*))?)?(([^?#]*)(\\?([^#]*))?(#(.*))?)"
  35. /*
  36. * Data types.
  37. */
  38. /// Language tag, currently restricted to 7 characters.
  39. typedef char LSUP_LangTag[8];
  40. /// Term type.
  41. typedef enum {
  42. LSUP_TERM_UNDEFINED = 0,/**<
  43. * Undefined placeholder or result of an error.
  44. * Invalid for most operations.
  45. */
  46. LSUP_TERM_IRIREF, ///< IRI reference.
  47. LSUP_TERM_NS_IRIREF, ///< Namespace-prefixed IRI reference.
  48. LSUP_TERM_LITERAL, ///< Literal without language tag.
  49. LSUP_TERM_LT_LITERAL, ///< Language-tagged string literal.
  50. LSUP_TERM_BNODE, ///< Blank node.
  51. } LSUP_TermType;
  52. /** @brief IRI information.
  53. *
  54. * See regex matching group for #LSUP_URI_REGEX_STR for more information.
  55. */
  56. typedef struct iri_info_t LSUP_IRIInfo;
  57. typedef struct link_map_iter LSUP_LinkMapIterator;
  58. /// RDF term.
  59. typedef struct term_t {
  60. char * data; // URI, literal value, or BNode label.
  61. union {
  62. struct term_t * datatype; // Data type IRI for LSUP_TERM_LITERAL.
  63. LSUP_LangTag lang; // Lang tag for LSUP_TERM_LT_LITERAL.
  64. LSUP_Key bnode_id; // BNode ID for comparison & skolemization.
  65. LSUP_IRIInfo * iri_info; // IRI information structure.
  66. };
  67. LSUP_TermType type; // Term type.
  68. } LSUP_Term;
  69. /** @brief Shorthand to test if a term is a IRI of any kind.
  70. */
  71. #define LSUP_IS_IRI(term) \
  72. ((term)->type == LSUP_TERM_IRIREF || (term)->type == LSUP_TERM_NS_IRIREF)
  73. /** @brief Shorthand to test if a term is a literal of any kind.
  74. */
  75. #define LSUP_IS_LITERAL(term) \
  76. ((term)->type == LSUP_TERM_LITERAL || (term)->type == LSUP_TERM_LT_LITERAL)
  77. /** @brief Whether the environment is already initialized.
  78. *
  79. * @TODO Check if the default NS was inserted; this would be slower but more
  80. * accurate.
  81. */
  82. #define LSUP_IS_INIT (LSUP_term_cache != NULL)
  83. /** @brief RDF triple.
  84. *
  85. * This represents a complete RDF statement. Triple terms can be accessed
  86. * directly via the `s`, `p`, `o` members or sequentially via
  87. * #LSUP_triple_pos().
  88. */
  89. typedef struct triple_t {
  90. LSUP_Term *s; ///< Subject.
  91. LSUP_Term *p; ///< Predicate.
  92. LSUP_Term *o; ///< Object.
  93. } LSUP_Triple;
  94. /// Link type.
  95. typedef enum {
  96. LSUP_LINK_INBOUND, ///< Inbound link (sp).
  97. LSUP_LINK_OUTBOUND, ///< Outbound link (po).
  98. LSUP_LINK_EDGE, ///< Edge link (so).
  99. } LSUP_LinkType;
  100. /** @brief The immediate neighborhood of terms connected to a term.
  101. *
  102. * This is a hash map whose each term is related to a set of one or more other
  103. * terms. The hash map is inside an opaque handle and is manipulated via the
  104. * `LSUP_link_map_*` functions.
  105. *
  106. * If the type of the link map is `LSUP_LINK_INBOUND`, the map keys
  107. * represent predicates and the sets related to them are the objects, and the
  108. * term associated to the link map is the object; if
  109. * `LSUP_LINK_OUTBOUND`, the keys represent predicates, the related sets
  110. * objects, and the associated term is the subject. If `LSUP_LINK_EDGE`, the
  111. * keys represent subjects and the related sets objects, and the associated
  112. * term is the predicate.
  113. */
  114. typedef struct link_map LSUP_LinkMap;
  115. /** @brief a set of unique terms.
  116. *
  117. * This is used to bulk-add terms to a link map.
  118. */
  119. typedef struct hashmap LSUP_TermSet;
  120. /*
  121. * External variables.
  122. */
  123. /** @brief Compiled hash of default literal data type.
  124. */
  125. extern uint32_t LSUP_default_dtype_key;
  126. /** @brief Default literal data type URI.
  127. *
  128. * Literal terms created with undefined data type will have it set to this
  129. * URI implicitly.
  130. */
  131. extern LSUP_Term *LSUP_default_datatype;
  132. /** @brief Global term cache.
  133. *
  134. * Stores frequently used terms, e.g. data type URIs.
  135. */
  136. extern LSUP_TermSet *LSUP_term_cache;
  137. /*
  138. * API functions.
  139. */
  140. /** @brief Create a new term.
  141. *
  142. * This is a generic function; it is recommended to use specialized functions
  143. * such as #LSUP_term_new(), #LSUP_literal_new(), etc. as they have strict type
  144. * checks for the metadata parameter.
  145. *
  146. * @param type[in] Term type. One of #LSUP_TermType.
  147. *
  148. * @param data[in] Term data: textual URI, literal value without data type
  149. * or langtag, etc. It may be NULL for IRI refs and BNodes, in which case a
  150. * random identifier is generated.
  151. *
  152. * @param metadata[in] Namespace map (LSUP_NSMap *) for IRI refs; language tag
  153. * (LSUP_LangTag *) for language-tagged literals; or data type (LSUP_Term *)
  154. * for other literals. It may be NULL.
  155. *
  156. * @return New term, which must be freed with #LSUP_term_free after use; or
  157. * NULL on error.
  158. */
  159. LSUP_Term *
  160. LSUP_term_new (LSUP_TermType type, const char *data, void *metadata);
  161. /** @brief Placeholder term to use with LSUP_term_reset.
  162. */
  163. #define TERM_DUMMY LSUP_term_new (LSUP_TERM_UNDEFINED, NULL, NULL)
  164. /** @brief Shortcut to create an IRI reference.
  165. *
  166. * Must be freed with #LSUP_term_free.
  167. *
  168. * @param data[in] The URI string. If NULL, a UUID4-based URN is generated.
  169. * This cannot be NULL if the nsm parameter is not NULL.
  170. *
  171. * @param nsm[in] Namespace map. If not NULL, a namespace-prefixed
  172. * (#LSUP_TERM_NS_IRIREF) is created, otherwise a regular one
  173. * (#LSUP_TERM_IRIREF).
  174. *
  175. * @return same as #LSUP_term_new().
  176. */
  177. inline LSUP_Term *
  178. LSUP_iriref_new (const char *data, LSUP_NSMap *nsm)
  179. {
  180. return (
  181. nsm ? LSUP_term_new (LSUP_TERM_NS_IRIREF, data, nsm) :
  182. LSUP_term_new (LSUP_TERM_IRIREF, data, NULL));
  183. }
  184. /** @brief Create a new absolute IRI from a path relative to a root IRI.
  185. *
  186. * The term is always of type LSUP_TERM_IRIREF (i.e. not namespace-prefixed).
  187. *
  188. * If the provided IRI is already a fully qualified IRI (i.e. it has a prefix)
  189. * the result is semantically identical to the input.
  190. *
  191. * If the relative IRI begins with a '/', the resulting IRI is relative to the
  192. * web root of the root IRI. I.e. if a root IRI has a path after the webroot,
  193. * it is ignored.
  194. *
  195. * Otherwise, the resulting IRI is relative to the full root string.
  196. *
  197. * @param[in] root Root IRI that the new IRI should be relative to.
  198. *
  199. * @param[in] iri Term with an IRI relative to the webroot.
  200. *
  201. * @return New absolute IRI, or NULL if either term is not an IRI.
  202. */
  203. LSUP_Term *
  204. LSUP_iriref_absolute (const LSUP_Term *root, const LSUP_Term *iri);
  205. /** @brief Create a new relative IRI from an absolute IRI and a web root IRI.
  206. *
  207. * This works with namespace-prefixed IRIs and returns a term of the same type
  208. * as the input.
  209. *
  210. * @param[in] iri Full IRI.
  211. *
  212. * @param[in] root Root IRI that the new IRI should be relative to.
  213. *
  214. * @return New IRI, or NULL if either term is not an IRI. If the input IRI is
  215. * not a path under the root IRI, the result will be identical to the input.
  216. */
  217. LSUP_Term *
  218. LSUP_iriref_relative (const LSUP_Term *root, const LSUP_Term *iri);
  219. /** @brief Shortcut to create a literal term.
  220. *
  221. * Must be freed with #LSUP_term_free.
  222. *
  223. * @param data[in] The literal string.
  224. *
  225. * @param datatype[in] Data type URI string. If NULL, the default data type
  226. * (xsd:string) is used. The new term takes ownership of the pointer.
  227. *
  228. * @return same as #LSUP_term_new().
  229. */
  230. inline LSUP_Term *
  231. LSUP_literal_new (const char *data, LSUP_Term *datatype)
  232. { return LSUP_term_new (LSUP_TERM_LITERAL, data, datatype); }
  233. /** @brief Shortcut to create a language-tagged literal term.
  234. *
  235. * Must be freed with #LSUP_term_free.
  236. *
  237. * @param data[in] The literal string.
  238. *
  239. * @param lang[in] Language tag string.
  240. *
  241. * @return same as #LSUP_term_new().
  242. */
  243. inline LSUP_Term *
  244. LSUP_lt_literal_new (const char *data, char *lang)
  245. { return LSUP_term_new (LSUP_TERM_LT_LITERAL, data, lang); }
  246. /** @brief Shortcut to create a blank node.
  247. *
  248. * Must be freed with #LSUP_term_free.
  249. *
  250. * @param data[in] The BNode identifier.
  251. *
  252. * @return same as #LSUP_term_new().
  253. */
  254. inline LSUP_Term *
  255. LSUP_bnode_new (const char *data)
  256. { return LSUP_term_new (LSUP_TERM_BNODE, data, NULL); }
  257. /** @brief Copy a term.
  258. *
  259. * @param[in] src The term to copy.
  260. *
  261. * @return A new duplicate term handle.
  262. */
  263. LSUP_Term *
  264. LSUP_term_copy (const LSUP_Term *src);
  265. /** @brief Deserialize a buffer into a term.
  266. *
  267. * @param[in] sterm Buffer to convert into a term. It must be a valid
  268. * serialized term from store or obtained with #LSUP_term_serialize().
  269. *
  270. * @return New term handle. It must be freed with #LSUP_term_free().
  271. */
  272. LSUP_Term *
  273. LSUP_term_new_from_buffer (const LSUP_Buffer *sterm);
  274. /** @brief Serialize a term into a buffer.
  275. *
  276. * @param[in] sterm Term to convert into a buffer.
  277. *
  278. * @return New buffer handle. It must be freed with #LSUP_buffer_free().
  279. */
  280. LSUP_Buffer *
  281. LSUP_term_serialize (const LSUP_Term *term);
  282. /** @brief Hash a buffer.
  283. */
  284. LSUP_Key
  285. LSUP_term_hash (const LSUP_Term *term);
  286. /** @brief Compare two terms.
  287. *
  288. * The terms evaluate as equal if their hashes are equal—i.e. if they are
  289. * semantically equivalent.
  290. */
  291. inline bool LSUP_term_equals (const LSUP_Term *term1, const LSUP_Term *term2)
  292. { return LSUP_term_hash (term1) == LSUP_term_hash (term2); }
  293. void
  294. LSUP_term_free (LSUP_Term *term);
  295. /** @brief Namespace map of a IRI ref.
  296. *
  297. * @param[in] iri IRI reference handle.
  298. *
  299. * @return A pointer to the namespace map associated with the IRI. It is
  300. * freed at program shutdown.
  301. */
  302. LSUP_NSMap *
  303. LSUP_iriref_nsm (const LSUP_Term *iri);
  304. /** @brief Get the prefix portion of a IRI ref.
  305. *
  306. * @param[in] iri IRI reference handle.
  307. *
  308. * @return String containing the protocol and domain name part of the IRI. It
  309. * should be freed after use.
  310. */
  311. char *
  312. LSUP_iriref_prefix (const LSUP_Term *iri);
  313. /** @brief Get the path portion of a IRI ref.
  314. *
  315. * @param[in] iri IRI reference handle.
  316. *
  317. * @return String containing the path of the IRI relative to the web root. For
  318. * a URN, such as `urn:myns:myid`, it would be `myns:myid`. This string should
  319. * be freed after use.
  320. */
  321. char *
  322. LSUP_iriref_path (const LSUP_Term *iri);
  323. /** @brief Get the fragment portion of a IRI ref.
  324. *
  325. * @param[in] iri IRI reference handle.
  326. *
  327. * @return String containing the fragment part of the IRI, or NULL if the IRI
  328. * contains no fragment. It should be freed after use.
  329. */
  330. char *
  331. LSUP_iriref_frag (const LSUP_Term *iri);
  332. /*
  333. * TRIPLES
  334. */
  335. /** @brief Create a new triple from three terms.
  336. *
  337. * Terms are NOT copied. To free them with the triple, use #LSUP_triple_free().
  338. * To only free the triple, use free().
  339. *
  340. * TODO Term types are not validated at the moment.
  341. *
  342. * @param[in] s Triple subject. It must be an IRIRef or BNode.
  343. *
  344. * @param[in] p Triple predicate. It must be an IRIRef.
  345. *
  346. * @param[in] o Triple object.
  347. *
  348. */
  349. LSUP_Triple *
  350. LSUP_triple_new(LSUP_Term *s, LSUP_Term *p, LSUP_Term *o);
  351. /** @brief Dummy triple with NULL slots. It is not a valid triple.
  352. */
  353. #define TRP_DUMMY LSUP_triple_new (NULL, NULL, NULL)
  354. LSUP_Triple *
  355. LSUP_triple_new_from_btriple (const LSUP_BufferTriple *sspo);
  356. LSUP_BufferTriple *
  357. LSUP_triple_serialize (const LSUP_Triple *spo);
  358. /** @brief Initialize internal term pointers in a heap-allocated triple.
  359. *
  360. * Terms are NOT copied. To free them with the triple, use #LSUP_triple_free().
  361. * To only free the triple, use free().
  362. *
  363. * @param spo[in] Triple pointer to initialize.
  364. */
  365. LSUP_rc
  366. LSUP_triple_init (LSUP_Triple *spo, LSUP_Term *s, LSUP_Term *p, LSUP_Term *o);
  367. /** @brief Free the internal pointers of a triple.
  368. *
  369. * @param spo[in] Triple to be freed.
  370. */
  371. void
  372. LSUP_triple_done (LSUP_Triple *spo);
  373. /** @brief Free a triple and all its internal pointers.
  374. *
  375. * NOTE: If the term pointers are not to be freed (e.g. they are owned by a
  376. * back end), use a simple free(spo) instead of this.
  377. *
  378. * @param spo[in] Triple to be freed.
  379. */
  380. void
  381. LSUP_triple_free (LSUP_Triple *spo);
  382. /** @brief Get triple by term position.
  383. *
  384. * Useful for looping over all terms.
  385. *
  386. * @param trp[in] Triple pointer.
  387. *
  388. * @param n[in] A number between 0÷2.
  389. *
  390. * @return Corresponding triple term or NULL if n is out of range.
  391. */
  392. inline LSUP_Term *
  393. LSUP_triple_pos (const LSUP_Triple *trp, LSUP_TriplePos n)
  394. {
  395. if (n == TRP_POS_S) return trp->s;
  396. if (n == TRP_POS_P) return trp->p;
  397. if (n == TRP_POS_O) return trp->o;
  398. return NULL;
  399. }
  400. /** @brief Hash a triple.
  401. *
  402. * TODO This doesn't handle blank nodes correctly.
  403. */
  404. inline LSUP_Key
  405. LSUP_triple_hash (const LSUP_Triple *trp)
  406. {
  407. LSUP_BufferTriple *strp = LSUP_triple_serialize (trp);
  408. LSUP_Key hash = LSUP_btriple_hash (strp);
  409. LSUP_btriple_free (strp);
  410. return hash;
  411. }
  412. /** @brief Create a new term set.
  413. *
  414. * @return New empty term set.
  415. */
  416. LSUP_TermSet *
  417. LSUP_term_set_new (void);
  418. /** @brief Free a term set.
  419. *
  420. * @param[in] ts Term set handle.
  421. */
  422. void
  423. LSUP_term_set_free (LSUP_TermSet *ts);
  424. /** @brief Add term to a term set.
  425. *
  426. * If the same term is already in the set, it is not replaced, and the existing
  427. * term's handle is made available in the `existing` variable. In this case,
  428. * the caller may want to free the passed term which has not been added.
  429. *
  430. * @param[in] tl Term set to be added to.
  431. *
  432. * @param[in] term Term to be added to the list. The term set will take
  433. * ownership of the term and free it when it's freed with
  434. * #LSUP_term_set_free()—only if the return code is LSUP_OK.
  435. *
  436. * @param[out] existing If not NULL, and if the term being added is a
  437. * duplicate, this variable will be populated with the existing term handle.
  438. *
  439. * @return LSUP_OK on success; LSUP_NOACTION if the term is duplicate;
  440. * LSUP_MEM_ERR on memory error. Note: if not LSUP_OK, the caller is in charge
  441. * of freeing the `term` handle.
  442. */
  443. LSUP_rc
  444. LSUP_term_set_add (LSUP_TermSet *ts, LSUP_Term *term, LSUP_Term **existing);
  445. /** @brief Get a term from a term set.
  446. *
  447. * @param[in] ts Term set handle.
  448. *
  449. * @param[in] key Key for the queried term.
  450. *
  451. * @return The retrieved term if found, or NULL. The term must not be
  452. * modified or freed.
  453. */
  454. const LSUP_Term *
  455. LSUP_term_set_get (LSUP_TermSet *ts, LSUP_Key key);
  456. /** @brief Iterate trough a term set.
  457. *
  458. * @param[in] ts Term set handle.
  459. *
  460. * @param[in,out] i Iterator to be initially set to 0.
  461. *
  462. * @param[out] term Pointer to be populated with the next term on success. It
  463. * may be NULL.
  464. *
  465. * @return LSUP_OK if the next term was retrieved; LSUP_END if the end of the
  466. * set has been reached.
  467. */
  468. LSUP_rc
  469. LSUP_term_set_next (LSUP_TermSet *ts, size_t *i, LSUP_Term **term);
  470. /** @brief New link map.
  471. *
  472. * The initial state of the returned list is: `{t: [NULL], tl: [NULL]}`
  473. *
  474. * Predicates and term lists can be added with #LSUP_link_map_add, and terms
  475. * can be added to a term list with #LSUP_term_list_add.
  476. *
  477. * @return a new empty predicate-object list.
  478. */
  479. LSUP_LinkMap *
  480. LSUP_link_map_new (LSUP_LinkType type);
  481. /** @brief Free a link map.
  482. *
  483. * All arrays and term handles are recursively freed.
  484. *
  485. * @param[in] pol link map handle obtained with #LSUP_link_map_new().
  486. */
  487. void
  488. LSUP_link_map_free (LSUP_LinkMap *pol);
  489. /// Return the link map type.
  490. LSUP_LinkType
  491. LSUP_link_map_type (const LSUP_LinkMap *map);
  492. /** @brief Add a term - term set pair to a link map.
  493. *
  494. * If there is already a term set for the given term, items from the added term
  495. * are added to the existing term set (if not duplicated). Otherwise, the term
  496. * set handle is linked to the new term.
  497. *
  498. * In any case, the caller should not directly use the term and term set after
  499. * passing them to this function.
  500. *
  501. * @param[in] cm Link map handle obtained with #LSUP_link_map_new().
  502. *
  503. * @param[in] t Term to be associated with the given object list. The
  504. * link map structure takes ownership of the term.
  505. *
  506. * @param[in] ts term set to be associated with the given term. The link
  507. * list structire takes ownership of the term set and the terms in it.
  508. *
  509. * @return LSUP_OK on success; LSUP_MEM_ERR on allocation error.
  510. */
  511. LSUP_rc
  512. LSUP_link_map_add (
  513. LSUP_LinkMap *cmap, LSUP_Term *term, LSUP_TermSet *tset);
  514. /** @brief Create a new iterator to loop through a link map.
  515. *
  516. * @param[in] lmap Map handle to iterate.
  517. *
  518. * @param[in] ext External term to look for connections.
  519. */
  520. LSUP_LinkMapIterator *
  521. LSUP_link_map_iter_new (const LSUP_LinkMap *lmap, LSUP_Term *ext);
  522. /// Free a link map iterator.
  523. void
  524. LSUP_link_map_iter_free (LSUP_LinkMapIterator *it);
  525. /** @brief Iterate through a link map.
  526. *
  527. * Each call to this function yields a linked term and the related term set.
  528. *
  529. * @param[in] it Link map iterator obtained with #LSUP_link_map_iter_new().
  530. *
  531. * @param[out] lt Linked term returned.
  532. *
  533. * @param[out] ts Term set returned.
  534. *
  535. * @return LSUP_OK if a result was yielded; LSUP_END if the end of the link map
  536. * has been reached.
  537. */
  538. LSUP_rc
  539. LSUP_link_map_next (
  540. LSUP_LinkMapIterator *it, LSUP_Term **lt, LSUP_TermSet **ts);
  541. /**@brief Iterate over a link map and generate triples.
  542. *
  543. * Calling this function repeatedly builds triples for all the linked terms and
  544. * term sets in the map, based on a given related term.
  545. *
  546. * @param[in] it Link map iterator handle, obtained with
  547. * #LSUP_link_map_iter_new().
  548. *
  549. * @param[in] term Term to relate to the link map.
  550. *
  551. * @param[in|out] spo Result triple. The triple handle must be pre-allocated
  552. * (it may be TRP_DUMMY) and calls to this function will be set its memebers
  553. * to term handles owned by the link map. If rc != LSUP_OK, the contents are
  554. * undefined.
  555. *
  556. * @return LSUP_OK if a new triple was yielded; LSUP_END if the end of the loop
  557. * has been reached; <0 on error.
  558. */
  559. LSUP_rc
  560. LSUP_link_map_triples (
  561. LSUP_LinkMapIterator *it, LSUP_Triple *spo);
  562. #endif