1 /* 2 * client.c 3 * libpkgconf consumer lifecycle management 4 * 5 * SPDX-License-Identifier: pkgconf 6 * 7 * Copyright (c) 2016 pkgconf authors (see AUTHORS). 8 * 9 * Permission to use, copy, modify, and/or distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * This software is provided 'as is' and without any warranty, express or 14 * implied. In no event shall the authors be liable for any damages arising 15 * from the use of this software. 16 */ 17 18 #include <libpkgconf/config.h> 19 #include <libpkgconf/stdinc.h> 20 #include <libpkgconf/libpkgconf.h> 21 22 /* 23 * !doc 24 * 25 * libpkgconf `client` module 26 * ========================== 27 * 28 * The libpkgconf `client` module implements the `pkgconf_client_t` "client" object. 29 * Client objects store all necessary state for libpkgconf allowing for multiple instances to run 30 * in parallel. 31 * 32 * Client objects are not thread safe, in other words, a client object should not be shared across 33 * thread boundaries. 34 */ 35 36 static void 37 trace_path_list(const pkgconf_client_t *client, const char *desc, pkgconf_list_t *list) 38 { 39 const pkgconf_node_t *n; 40 41 PKGCONF_TRACE(client, "%s:", desc); 42 PKGCONF_FOREACH_LIST_ENTRY(list->head, n) 43 { 44 const pkgconf_path_t *p = n->data; 45 46 PKGCONF_TRACE(client, " - '%s'", p->path); 47 } 48 } 49 50 /* 51 * !doc 52 * 53 * .. c:function:: void pkgconf_client_dir_list_build(pkgconf_client_t *client) 54 * 55 * Bootstraps the package search paths. If the ``PKGCONF_PKG_PKGF_ENV_ONLY`` `flag` is set on the client, 56 * then only the ``PKG_CONFIG_PATH`` environment variable will be used, otherwise both the 57 * ``PKG_CONFIG_PATH`` and ``PKG_CONFIG_LIBDIR`` environment variables will be used. 58 * 59 * :param pkgconf_client_t* client: The pkgconf client object to bootstrap. 60 * :return: nothing 61 */ 62 void 63 pkgconf_client_dir_list_build(pkgconf_client_t *client, const pkgconf_cross_personality_t *personality) 64 { 65 pkgconf_path_build_from_environ(client, "PKG_CONFIG_PATH", NULL, &client->dir_list, true); 66 67 if (!(client->flags & PKGCONF_PKG_PKGF_ENV_ONLY)) 68 { 69 pkgconf_list_t dir_list = PKGCONF_LIST_INITIALIZER; 70 const pkgconf_list_t *prepend_list = &personality->dir_list; 71 72 #ifdef _WIN32 73 /* 74 * NOTE: setting the pkgconf path from the registry is deprecated 75 * and will be removed in pkgconf 3.1. 76 */ 77 (void) pkgconf_path_build_from_registry(client, HKEY_CURRENT_USER, &client->dir_list, true); 78 (void) pkgconf_path_build_from_registry(client, HKEY_LOCAL_MACHINE, &client->dir_list, true); 79 #endif 80 81 if (pkgconf_client_getenv(client, "PKG_CONFIG_LIBDIR") != NULL) 82 { 83 /* PKG_CONFIG_LIBDIR= should empty the search path entirely. */ 84 (void) pkgconf_path_build_from_environ(client, "PKG_CONFIG_LIBDIR", NULL, &dir_list, true); 85 prepend_list = &dir_list; 86 } 87 88 pkgconf_path_copy_list(&client->dir_list, prepend_list); 89 pkgconf_path_free(&dir_list); 90 } 91 } 92 93 /* 94 * !doc 95 * 96 * .. c:function:: void pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler) 97 * 98 * Initialise a pkgconf client object. 99 * 100 * :param pkgconf_client_t* client: The client to initialise. 101 * :param pkgconf_error_handler_func_t error_handler: An optional error handler to use for logging errors. 102 * :param void* error_handler_data: user data passed to optional error handler 103 * :param pkgconf_cross_personality_t* personality: the cross-compile personality to use for defaults 104 * :param void* client_data: user data associated with the client 105 * :param pkgconf_environ_lookup_handler_func_t environ_lookup_handler: the lookup handler to use for environment variables 106 * :return: nothing 107 */ 108 void 109 pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler) 110 { 111 client->personality = personality; 112 client->client_data = client_data; 113 client->environ_lookup_handler = environ_lookup_handler; 114 client->error_handler_data = error_handler_data; 115 client->error_handler = error_handler; 116 client->auditf = NULL; 117 client->cache_table = NULL; 118 client->cache_count = 0; 119 120 #ifndef PKGCONF_LITE 121 if (client->trace_handler == NULL) 122 pkgconf_client_set_trace_handler(client, NULL, NULL); 123 #endif 124 125 if (client->unveil_handler == NULL) 126 pkgconf_client_set_unveil_handler(client, NULL); 127 128 pkgconf_client_set_error_handler(client, error_handler, error_handler_data); 129 pkgconf_client_set_warn_handler(client, NULL, NULL); 130 131 pkgconf_client_set_sysroot_dir(client, personality->sysroot_dir); 132 pkgconf_client_set_buildroot_dir(client, NULL); 133 pkgconf_client_set_prefix_varname(client, NULL); 134 135 if(pkgconf_client_getenv(client, "PKG_CONFIG_SYSTEM_LIBRARY_PATH") == NULL) 136 pkgconf_path_copy_list(&client->filter_libdirs, &personality->filter_libdirs); 137 else 138 pkgconf_path_build_from_environ(client, "PKG_CONFIG_SYSTEM_LIBRARY_PATH", NULL, &client->filter_libdirs, false); 139 140 if(pkgconf_client_getenv(client, "PKG_CONFIG_SYSTEM_INCLUDE_PATH") == NULL) 141 pkgconf_path_copy_list(&client->filter_includedirs, &personality->filter_includedirs); 142 else 143 pkgconf_path_build_from_environ(client, "PKG_CONFIG_SYSTEM_INCLUDE_PATH", NULL, &client->filter_includedirs, false); 144 145 /* GCC uses these environment variables to define system include paths, so we should check them. */ 146 #ifdef __HAIKU__ 147 pkgconf_path_build_from_environ(client, "BELIBRARIES", NULL, &client->filter_libdirs, false); 148 #else 149 pkgconf_path_build_from_environ(client, "LIBRARY_PATH", NULL, &client->filter_libdirs, false); 150 #endif 151 pkgconf_path_build_from_environ(client, "CPATH", NULL, &client->filter_includedirs, false); 152 pkgconf_path_build_from_environ(client, "C_INCLUDE_PATH", NULL, &client->filter_includedirs, false); 153 pkgconf_path_build_from_environ(client, "CPLUS_INCLUDE_PATH", NULL, &client->filter_includedirs, false); 154 pkgconf_path_build_from_environ(client, "OBJC_INCLUDE_PATH", NULL, &client->filter_includedirs, false); 155 156 #ifdef _WIN32 157 /* also use the path lists that MSVC uses on windows */ 158 pkgconf_path_build_from_environ(client, "INCLUDE", NULL, &client->filter_includedirs, false); 159 #endif 160 161 PKGCONF_TRACE(client, "initialized client @%p", client); 162 163 trace_path_list(client, "filtered library paths", &client->filter_libdirs); 164 trace_path_list(client, "filtered include paths", &client->filter_includedirs); 165 166 client->output = pkgconf_output_default(); 167 } 168 169 /* 170 * !doc 171 * 172 * .. c:function:: pkgconf_client_t* pkgconf_client_new(pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality) 173 * 174 * Allocate and initialise a pkgconf client object. 175 * 176 * :param pkgconf_error_handler_func_t error_handler: An optional error handler to use for logging errors. 177 * :param void* error_handler_data: user data passed to optional error handler 178 * :param pkgconf_cross_personality_t* personality: cross-compile personality to use 179 * :param void* client_data: user data associated with the client 180 * :param pkgconf_environ_lookup_handler_func_t environ_lookup_handler: the lookup handler to use for environment variables 181 * :return: A pkgconf client object. 182 * :rtype: pkgconf_client_t* 183 */ 184 pkgconf_client_t * 185 pkgconf_client_new(pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler) 186 { 187 pkgconf_client_t *out = calloc(1, sizeof(pkgconf_client_t)); 188 if (out == NULL) 189 return NULL; 190 191 pkgconf_client_init(out, error_handler, error_handler_data, personality, client_data, environ_lookup_handler); 192 return out; 193 } 194 195 static void 196 unref_preload_list(pkgconf_client_t *client) 197 { 198 pkgconf_node_t *n, *tn; 199 200 PKGCONF_FOREACH_LIST_ENTRY_SAFE(client->preloaded_pkgs.head, tn, n) 201 { 202 pkgconf_pkg_t *pkg = n->data; 203 pkgconf_pkg_unref(client, pkg); 204 } 205 } 206 207 /* 208 * !doc 209 * 210 * .. c:function:: void pkgconf_client_deinit(pkgconf_client_t *client) 211 * 212 * Release resources belonging to a pkgconf client object. 213 * 214 * :param pkgconf_client_t* client: The client to deinitialise. 215 * :return: nothing 216 */ 217 void 218 pkgconf_client_deinit(pkgconf_client_t *client) 219 { 220 PKGCONF_TRACE(client, "deinit @%p", client); 221 222 unref_preload_list(client); 223 224 if (client->prefix_varname != NULL) 225 free(client->prefix_varname); 226 227 if (client->sysroot_dir != NULL) 228 free(client->sysroot_dir); 229 230 if (client->buildroot_dir != NULL) 231 free(client->buildroot_dir); 232 233 pkgconf_path_free(&client->filter_libdirs); 234 pkgconf_path_free(&client->filter_includedirs); 235 236 pkgconf_tuple_free_global(client); 237 pkgconf_path_free(&client->dir_list); 238 pkgconf_cache_free(client); 239 240 pkgconf_buffer_finalize(&client->_scratch_buffer); 241 242 memset(client, '\0', sizeof(*client)); 243 } 244 245 /* 246 * !doc 247 * 248 * .. c:function:: void pkgconf_client_free(pkgconf_client_t *client) 249 * 250 * Release resources belonging to a pkgconf client object and then free the client object itself. 251 * 252 * :param pkgconf_client_t* client: The client to deinitialise and free. 253 * :return: nothing 254 */ 255 void 256 pkgconf_client_free(pkgconf_client_t *client) 257 { 258 pkgconf_client_deinit(client); 259 free(client); 260 } 261 262 /* 263 * !doc 264 * 265 * .. c:function:: const char *pkgconf_client_get_sysroot_dir(const pkgconf_client_t *client) 266 * 267 * Retrieves the client's sysroot directory (if any). 268 * 269 * :param pkgconf_client_t* client: The client object being accessed. 270 * :return: A string containing the sysroot directory or NULL. 271 * :rtype: const char * 272 */ 273 const char * 274 pkgconf_client_get_sysroot_dir(const pkgconf_client_t *client) 275 { 276 return client->sysroot_dir; 277 } 278 279 /* 280 * !doc 281 * 282 * .. c:function:: void pkgconf_client_set_sysroot_dir(pkgconf_client_t *client, const char *sysroot_dir) 283 * 284 * Sets or clears the sysroot directory on a client object. Any previous sysroot directory setting is 285 * automatically released if one was previously set. 286 * 287 * Additionally, the global tuple ``$(pc_sysrootdir)`` is set as appropriate based on the new setting. 288 * 289 * :param pkgconf_client_t* client: The client object being modified. 290 * :param char* sysroot_dir: The sysroot directory to set or NULL to unset. 291 * :return: nothing 292 */ 293 void 294 pkgconf_client_set_sysroot_dir(pkgconf_client_t *client, const char *sysroot_dir) 295 { 296 if (sysroot_dir != NULL && (!strcmp(sysroot_dir, "/") || !strcmp(sysroot_dir, "."))) 297 { 298 pkgconf_warn(client, "ignoring bogus sysroot_dir: %s", sysroot_dir); 299 sysroot_dir = NULL; 300 } 301 302 if (client->sysroot_dir != NULL) 303 free(client->sysroot_dir); 304 305 client->sysroot_dir = sysroot_dir != NULL ? strdup(sysroot_dir) : NULL; 306 307 PKGCONF_TRACE(client, "set sysroot_dir to: %s", client->sysroot_dir != NULL ? client->sysroot_dir : "<default>"); 308 309 pkgconf_tuple_add_global(client, "pc_sysrootdir", client->sysroot_dir != NULL ? client->sysroot_dir : ""); 310 } 311 312 /* 313 * !doc 314 * 315 * .. c:function:: const char *pkgconf_client_get_buildroot_dir(const pkgconf_client_t *client) 316 * 317 * Retrieves the client's buildroot directory (if any). 318 * 319 * :param pkgconf_client_t* client: The client object being accessed. 320 * :return: A string containing the buildroot directory or NULL. 321 * :rtype: const char * 322 */ 323 const char * 324 pkgconf_client_get_buildroot_dir(const pkgconf_client_t *client) 325 { 326 return client->buildroot_dir; 327 } 328 329 /* 330 * !doc 331 * 332 * .. c:function:: void pkgconf_client_set_buildroot_dir(pkgconf_client_t *client, const char *buildroot_dir) 333 * 334 * Sets or clears the buildroot directory on a client object. Any previous buildroot directory setting is 335 * automatically released if one was previously set. 336 * 337 * Additionally, the global tuple ``$(pc_top_builddir)`` is set as appropriate based on the new setting. 338 * 339 * :param pkgconf_client_t* client: The client object being modified. 340 * :param char* buildroot_dir: The buildroot directory to set or NULL to unset. 341 * :return: nothing 342 */ 343 void 344 pkgconf_client_set_buildroot_dir(pkgconf_client_t *client, const char *buildroot_dir) 345 { 346 if (client->buildroot_dir != NULL) 347 free(client->buildroot_dir); 348 349 client->buildroot_dir = buildroot_dir != NULL ? strdup(buildroot_dir) : NULL; 350 351 PKGCONF_TRACE(client, "set buildroot_dir to: %s", client->buildroot_dir != NULL ? client->buildroot_dir : "<default>"); 352 353 pkgconf_tuple_add_global(client, "pc_top_builddir", client->buildroot_dir != NULL ? client->buildroot_dir : "$(top_builddir)"); 354 } 355 356 /* 357 * !doc 358 * 359 * .. c:function:: bool pkgconf_error(const pkgconf_client_t *client, const char *format, ...) 360 * 361 * Report an error to a client-registered error handler. 362 * 363 * :param pkgconf_client_t* client: The pkgconf client object to report the error to. 364 * :param char* format: A printf-style format string to use for formatting the error message. 365 * :return: true if the error handler processed the message, else false. 366 * :rtype: bool 367 */ 368 bool 369 pkgconf_error(const pkgconf_client_t *client, const char *format, ...) 370 { 371 char *errbuf; 372 ssize_t msgsize = 0; 373 bool ret; 374 va_list va; 375 376 va_start(va, format); 377 msgsize = vsnprintf(NULL, 0, format, va); 378 va_end(va); 379 380 if (msgsize < 0) 381 return false; 382 383 msgsize++; 384 385 errbuf = calloc(1, msgsize); 386 if (errbuf == NULL) 387 return false; 388 389 va_start(va, format); 390 vsnprintf(errbuf, msgsize, format, va); 391 va_end(va); 392 393 ret = client->error_handler(errbuf, client, client->error_handler_data); 394 free(errbuf); 395 396 return ret; 397 } 398 399 /* 400 * !doc 401 * 402 * .. c:function:: bool pkgconf_warn(const pkgconf_client_t *client, const char *format, ...) 403 * 404 * Report an error to a client-registered warn handler. 405 * 406 * :param pkgconf_client_t* client: The pkgconf client object to report the error to. 407 * :param char* format: A printf-style format string to use for formatting the warning message. 408 * :return: true if the warn handler processed the message, else false. 409 * :rtype: bool 410 */ 411 bool 412 pkgconf_warn(const pkgconf_client_t *client, const char *format, ...) 413 { 414 char *errbuf; 415 ssize_t msgsize = 0; 416 bool ret; 417 va_list va; 418 419 va_start(va, format); 420 msgsize = vsnprintf(NULL, 0, format, va); 421 va_end(va); 422 423 if (msgsize < 0) 424 return false; 425 426 msgsize++; 427 428 errbuf = calloc(1, msgsize); 429 if (errbuf == NULL) 430 return false; 431 432 va_start(va, format); 433 vsnprintf(errbuf, msgsize, format, va); 434 va_end(va); 435 436 ret = client->warn_handler(errbuf, client, client->warn_handler_data); 437 free(errbuf); 438 439 return ret; 440 } 441 442 /* 443 * !doc 444 * 445 * .. c:function:: bool pkgconf_trace(const pkgconf_client_t *client, const char *filename, size_t len, const char *funcname, const char *format, ...) 446 * 447 * Report a message to a client-registered trace handler. 448 * 449 * :param pkgconf_client_t* client: The pkgconf client object to report the trace message to. 450 * :param char* filename: The file the function is in. 451 * :param size_t lineno: The line number currently being executed. 452 * :param char* funcname: The function name to use. 453 * :param char* format: A printf-style format string to use for formatting the trace message. 454 * :return: true if the trace handler processed the message, else false. 455 * :rtype: bool 456 */ 457 bool 458 pkgconf_trace(const pkgconf_client_t *client, const char *filename, size_t lineno, const char *funcname, const char *format, ...) 459 { 460 char prefix[PKGCONF_ITEM_SIZE]; 461 char *errbuf = NULL; 462 ssize_t errlen; 463 char *finalbuf = NULL; 464 ssize_t finallen; 465 bool ret; 466 va_list va; 467 468 if (client == NULL || client->trace_handler == NULL) 469 return false; 470 471 snprintf(prefix, sizeof prefix, "%s:" SIZE_FMT_SPECIFIER " [%s]:", filename, lineno, funcname); 472 473 va_start(va, format); 474 errlen = vsnprintf(NULL, 0, format, va); 475 va_end(va); 476 477 if (errlen < 0) 478 return false; 479 480 errlen++; 481 errbuf = calloc(1, errlen); 482 if (errbuf == NULL) 483 return false; 484 485 va_start(va, format); 486 vsnprintf(errbuf, errlen, format, va); 487 va_end(va); 488 489 finallen = snprintf(NULL, 0, "%s %s\n", prefix, errbuf); 490 if (finallen < 0) 491 { 492 free(errbuf); 493 return false; 494 } 495 496 finallen++; 497 finalbuf = calloc(1, finallen); 498 if (finalbuf == NULL) 499 { 500 free(errbuf); 501 return false; 502 } 503 504 snprintf(finalbuf, finallen, "%s %s\n", prefix, errbuf); 505 ret = client->trace_handler(finalbuf, client, client->trace_handler_data); 506 free(errbuf); 507 free(finalbuf); 508 509 return ret; 510 } 511 512 /* 513 * !doc 514 * 515 * .. c:function:: bool pkgconf_default_error_handler(const char *msg, const pkgconf_client_t *client, const void *data) 516 * 517 * The default pkgconf error handler. 518 * 519 * :param char* msg: The error message to handle. 520 * :param pkgconf_client_t* client: The client object the error originated from. 521 * :param void* data: An opaque pointer to extra data associated with the client for error handling. 522 * :return: true (the function does nothing to process the message) 523 * :rtype: bool 524 */ 525 bool 526 pkgconf_default_error_handler(const char *msg, const pkgconf_client_t *client, void *data) 527 { 528 (void) msg; 529 (void) client; 530 (void) data; 531 532 return true; 533 } 534 535 static void 536 default_unveil_handler(const pkgconf_client_t *client, const char *path, const char *permissions) 537 { 538 (void) client; 539 (void) path; 540 (void) permissions; 541 } 542 543 /* 544 * !doc 545 * 546 * .. c:function:: unsigned int pkgconf_client_get_flags(const pkgconf_client_t *client) 547 * 548 * Retrieves resolver-specific flags associated with a client object. 549 * 550 * :param pkgconf_client_t* client: The client object to retrieve the resolver-specific flags from. 551 * :return: a bitfield of resolver-specific flags 552 * :rtype: uint 553 */ 554 unsigned int 555 pkgconf_client_get_flags(const pkgconf_client_t *client) 556 { 557 return client->flags; 558 } 559 560 /* 561 * !doc 562 * 563 * .. c:function:: void pkgconf_client_set_flags(pkgconf_client_t *client, unsigned int flags) 564 * 565 * Sets resolver-specific flags associated with a client object. 566 * 567 * :param pkgconf_client_t* client: The client object to set the resolver-specific flags on. 568 * :return: nothing 569 */ 570 void 571 pkgconf_client_set_flags(pkgconf_client_t *client, unsigned int flags) 572 { 573 client->flags = flags; 574 } 575 576 /* 577 * !doc 578 * 579 * .. c:function:: const char *pkgconf_client_get_prefix_varname(const pkgconf_client_t *client) 580 * 581 * Retrieves the name of the variable that should contain a module's prefix. 582 * In some cases, it is necessary to override this variable to allow proper path relocation. 583 * 584 * :param pkgconf_client_t* client: The client object to retrieve the prefix variable name from. 585 * :return: the prefix variable name as a string 586 * :rtype: const char * 587 */ 588 const char * 589 pkgconf_client_get_prefix_varname(const pkgconf_client_t *client) 590 { 591 return client->prefix_varname; 592 } 593 594 /* 595 * !doc 596 * 597 * .. c:function:: void pkgconf_client_set_prefix_varname(pkgconf_client_t *client, const char *prefix_varname) 598 * 599 * Sets the name of the variable that should contain a module's prefix. 600 * If the variable name is ``NULL``, then the default variable name (``prefix``) is used. 601 * 602 * :param pkgconf_client_t* client: The client object to set the prefix variable name on. 603 * :param char* prefix_varname: The prefix variable name to set. 604 * :return: nothing 605 */ 606 void 607 pkgconf_client_set_prefix_varname(pkgconf_client_t *client, const char *prefix_varname) 608 { 609 if (prefix_varname == NULL) 610 prefix_varname = "prefix"; 611 612 if (client->prefix_varname != NULL) 613 free(client->prefix_varname); 614 615 client->prefix_varname = strdup(prefix_varname); 616 617 PKGCONF_TRACE(client, "set prefix_varname to: %s", client->prefix_varname); 618 } 619 620 /* 621 * !doc 622 * 623 * .. c:function:: pkgconf_client_get_warn_handler(const pkgconf_client_t *client) 624 * 625 * Returns the warning handler if one is set, else ``NULL``. 626 * 627 * :param pkgconf_client_t* client: The client object to get the warn handler from. 628 * :return: a function pointer to the warn handler or ``NULL`` 629 */ 630 pkgconf_error_handler_func_t 631 pkgconf_client_get_warn_handler(const pkgconf_client_t *client) 632 { 633 return client->warn_handler; 634 } 635 636 /* 637 * !doc 638 * 639 * .. c:function:: pkgconf_client_set_warn_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t warn_handler, void *warn_handler_data) 640 * 641 * Sets a warn handler on a client object or uninstalls one if set to ``NULL``. 642 * 643 * :param pkgconf_client_t* client: The client object to set the warn handler on. 644 * :param pkgconf_error_handler_func_t warn_handler: The warn handler to set. 645 * :param void* warn_handler_data: Optional data to associate with the warn handler. 646 * :return: nothing 647 */ 648 void 649 pkgconf_client_set_warn_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t warn_handler, void *warn_handler_data) 650 { 651 client->warn_handler = warn_handler; 652 client->warn_handler_data = warn_handler_data; 653 654 if (client->warn_handler == NULL) 655 { 656 PKGCONF_TRACE(client, "installing default warn handler"); 657 client->warn_handler = pkgconf_default_error_handler; 658 } 659 } 660 661 /* 662 * !doc 663 * 664 * .. c:function:: pkgconf_client_get_error_handler(const pkgconf_client_t *client) 665 * 666 * Returns the error handler if one is set, else ``NULL``. 667 * 668 * :param pkgconf_client_t* client: The client object to get the error handler from. 669 * :return: a function pointer to the error handler or ``NULL`` 670 */ 671 pkgconf_error_handler_func_t 672 pkgconf_client_get_error_handler(const pkgconf_client_t *client) 673 { 674 return client->error_handler; 675 } 676 677 /* 678 * !doc 679 * 680 * .. c:function:: pkgconf_client_set_error_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data) 681 * 682 * Sets a warn handler on a client object or uninstalls one if set to ``NULL``. 683 * 684 * :param pkgconf_client_t* client: The client object to set the error handler on. 685 * :param pkgconf_error_handler_func_t error_handler: The error handler to set. 686 * :param void* error_handler_data: Optional data to associate with the error handler. 687 * :return: nothing 688 */ 689 void 690 pkgconf_client_set_error_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data) 691 { 692 client->error_handler = error_handler; 693 client->error_handler_data = error_handler_data; 694 695 if (client->error_handler == NULL) 696 { 697 PKGCONF_TRACE(client, "installing default error handler"); 698 client->error_handler = pkgconf_default_error_handler; 699 } 700 } 701 702 /* 703 * !doc 704 * 705 * .. c:function:: pkgconf_client_get_unveil_handler(const pkgconf_client_t *client) 706 * 707 * Returns the unveil handler if one is set, else ``NULL``. 708 * 709 * :param pkgconf_client_t* client: The client object to get the unveil handler from. 710 * :return: a function pointer to the error handler or ``NULL`` 711 */ 712 pkgconf_unveil_handler_func_t 713 pkgconf_client_get_unveil_handler(const pkgconf_client_t *client) 714 { 715 return client->unveil_handler; 716 } 717 718 /* 719 * !doc 720 * 721 * .. c:function:: pkgconf_client_set_unveil_handler(pkgconf_client_t *client, pkgconf_unveil_handler_func_t unveil_handler) 722 * 723 * Sets an unveil handler on a client object or uninstalls one if set to ``NULL``. 724 * 725 * :param pkgconf_client_t* client: The client object to set the error handler on. 726 * :param pkgconf_unveil_handler_func_t unveil_handler: The unveil handler to set. 727 * :return: nothing 728 */ 729 void 730 pkgconf_client_set_unveil_handler(pkgconf_client_t *client, pkgconf_unveil_handler_func_t unveil_handler) 731 { 732 client->unveil_handler = unveil_handler; 733 734 if (client->unveil_handler == NULL) 735 { 736 PKGCONF_TRACE(client, "installing default unveil handler"); 737 client->unveil_handler = default_unveil_handler; 738 } 739 } 740 741 #ifndef PKGCONF_LITE 742 /* 743 * !doc 744 * 745 * .. c:function:: pkgconf_client_get_trace_handler(const pkgconf_client_t *client) 746 * 747 * Returns the error handler if one is set, else ``NULL``. 748 * 749 * :param pkgconf_client_t* client: The client object to get the error handler from. 750 * :return: a function pointer to the error handler or ``NULL`` 751 */ 752 pkgconf_error_handler_func_t 753 pkgconf_client_get_trace_handler(const pkgconf_client_t *client) 754 { 755 return client->trace_handler; 756 } 757 758 /* 759 * !doc 760 * 761 * .. c:function:: pkgconf_client_set_trace_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t trace_handler, void *trace_handler_data) 762 * 763 * Sets a warn handler on a client object or uninstalls one if set to ``NULL``. 764 * 765 * :param pkgconf_client_t* client: The client object to set the error handler on. 766 * :param pkgconf_error_handler_func_t trace_handler: The error handler to set. 767 * :param void* trace_handler_data: Optional data to associate with the error handler. 768 * :return: nothing 769 */ 770 void 771 pkgconf_client_set_trace_handler(pkgconf_client_t *client, pkgconf_error_handler_func_t trace_handler, void *trace_handler_data) 772 { 773 client->trace_handler = trace_handler; 774 client->trace_handler_data = trace_handler_data; 775 776 if (client->trace_handler == NULL) 777 { 778 client->trace_handler = pkgconf_default_error_handler; 779 PKGCONF_TRACE(client, "installing default trace handler"); 780 } 781 } 782 #endif 783 784 /* 785 * !doc 786 * 787 * .. c:function:: bool pkgconf_client_preload_one(pkgconf_client_t *client, pkgconf_pkg_t *pkg) 788 * 789 * Adds a package to the preloaded packages set. 790 * 791 * :param pkgconf_client_t* client: The client object for preloading. 792 * :param pkgconf_pkg_t* pkg: The package to preload. 793 * :return: true on success, false on error 794 * :rtype: bool 795 */ 796 bool 797 pkgconf_client_preload_one(pkgconf_client_t *client, pkgconf_pkg_t *pkg) 798 { 799 PKGCONF_TRACE(client, "preloading pkg %s@%p", pkg->id, pkg); 800 801 pkg->flags |= PKGCONF_PKG_PROPF_PRELOADED; 802 803 pkgconf_pkg_ref(client, pkg); 804 pkgconf_node_insert_tail(&pkg->preload_node, pkg, &client->preloaded_pkgs); 805 806 return true; 807 } 808 809 /* 810 * !doc 811 * 812 * .. c:function:: bool pkgconf_client_preload_path(pkgconf_client_t *client, const char *path) 813 * 814 * Loads a pkg-config file into the preloaded packages set. 815 * 816 * :param pkgconf_client_t* client: The client object for preloading. 817 * :param char* path: The path to the pkg-config file to preload. 818 * :return: true on success, false on error 819 * :rtype: bool 820 */ 821 bool 822 pkgconf_client_preload_path(pkgconf_client_t *client, const char *path) 823 { 824 pkgconf_pkg_t *pkg = pkgconf_pkg_new_from_path(client, path, PKGCONF_PKG_PROPF_PRELOADED); 825 if (pkg == NULL) 826 return false; 827 828 return pkgconf_client_preload_one(client, pkg); 829 } 830 831 /* 832 * !doc 833 * 834 * .. c:function:: bool pkgconf_client_preload_from_environ(pkgconf_client_t *client, const char *env) 835 * 836 * Loads zero or more pkg-config files specified in the given environmental 837 * variable. 838 * 839 * :param pkgconf_client_t* client: The client object for preloading. 840 * :param char* environ: The environment variable to use for preloading. 841 * :return: true on success, false on error 842 * :rtype: bool 843 */ 844 bool 845 pkgconf_client_preload_from_environ(pkgconf_client_t *client, const char *env) 846 { 847 const char *data; 848 pkgconf_list_t pathlist = PKGCONF_LIST_INITIALIZER; 849 pkgconf_node_t *n; 850 bool ret = true; 851 852 data = pkgconf_client_getenv(client, env); 853 if (data == NULL) 854 return true; 855 856 pkgconf_path_split(data, &pathlist, true); 857 858 PKGCONF_FOREACH_LIST_ENTRY(pathlist.head, n) 859 { 860 pkgconf_path_t *pn = n->data; 861 862 ret = pkgconf_client_preload_path(client, pn->path); 863 if (!ret) 864 break; 865 } 866 867 pkgconf_path_free(&pathlist); 868 869 return ret; 870 } 871 872 /* 873 * !doc 874 * 875 * .. c:function:: void pkgconf_client_set_output(pkgconf_client_t *client, pkgconf_output_t *output) 876 * 877 * Sets the client's output object. This is mainly a convenience function for clients 878 * to use. 879 * 880 * :param pkgconf_client_t* client: The client object to set the output object for. 881 * :param pkgconf_output_t* output: The output object to use. 882 * :return: nothing 883 */ 884 void 885 pkgconf_client_set_output(pkgconf_client_t *client, pkgconf_output_t *output) 886 { 887 client->output = output; 888 } 889 890 /* 891 * !doc 892 * 893 * .. c:function:: const char *pkgconf_client_getenv(const pkgconf_client_t *client, const char *key) 894 * 895 * Looks up an environmental variable which may be mocked, otherwise fetches 896 * from the main environment. 897 * 898 * :param pkgconf_client_t* client: yhe client object to use for looking up environmental variables. 899 * :param char* key: the environmental variable to look up. 900 * :return: the environmental variable contents else NULL 901 * :rtype: const char* 902 */ 903 const char * 904 pkgconf_client_getenv(const pkgconf_client_t *client, const char *key) 905 { 906 if (client != NULL && client->environ_lookup_handler != NULL) 907 return client->environ_lookup_handler(client, key); 908 909 return getenv(key); 910 } 911