LIBPSL(3)

πŸ’– LIBPSL(3) πŸ’–

okay so bestie, welcome to LIBPSL(3), aka the manual page for the LIBPSL Library 🫢 this is the whole Public Suffix List library, and by the end you're gonna know it like the back of your hand. no cap.


✨ NAME ✨

libpsl β€” Public Suffix List library functions 🌈


πŸ›‘οΈ STABILITY LEVEL πŸ›‘οΈ

Stable, unless otherwise indicated. (iconic behaviour, honestly)


πŸ“œ FUNCTIONS πŸ“œ

here's the whole lineup, bestie, in order πŸ‘‘

psl_ctx_t *                           psl_load_file ()
psl_ctx_t *                           psl_load_fp ()
psl_ctx_t *                           psl_latest ()
const psl_ctx_t *                     psl_builtin ()
void                                  psl_free ()
int                                   psl_is_public_suffix ()
int                                   psl_is_public_suffix2 ()
const char *                          psl_unregistrable_domain ()
const char *                          psl_registrable_domain ()
int                                   psl_suffix_count ()
int                                   psl_suffix_exception_count ()
int                                   psl_suffix_wildcard_count ()
time_t                                psl_builtin_file_time ()
const char *                          psl_builtin_sha1sum ()
const char *                          psl_builtin_filename ()
int                                   psl_builtin_outdated ()
int                                   psl_is_cookie_domain_acceptable ()
const char *                          psl_dist_filename ()
const char *                          psl_get_version ()
int                                   psl_check_version_number ()
psl_error_t                           psl_str_to_utf8lower ()
void                                  psl_free_string ()

🧬 TYPES AND VALUES 🧬

the vibes (and the defines) you're working with πŸ’…

#define                                            PSL_API
#define                                            PSL_VERSION
#define                                            PSL_VERSION_MAJOR
#define                                            PSL_VERSION_MINOR
#define                                            PSL_VERSION_NUMBER
#define                                            PSL_VERSION_PATCH
#define                                            PSL_TYPE_ICANN
#define                                            PSL_TYPE_PRIVATE
#define                                            PSL_TYPE_NO_STAR_RULE
#define                                            PSL_TYPE_ANY
enum                                               psl_error_t
typedef                                            psl_ctx_t

πŸ“¦ INCLUDES πŸ“¦

just this one, diva πŸŽ€

#include <libpsl.h>

🌸 DESCRIPTION 🌸

Public Suffix List[1] library functions. literally that. that's the description. periodt. πŸ’…


🧚 FUNCTIONS (for real this time) 🧚

🌟 psl_load_file ()

psl_ctx_t *
psl_load_file (const char *fname);

bestie this one loads up the public suffixes file you point it at with fname. when you're done with the precious resources it allocates, call psl_free() or else 🫠

if the suffixes are international, they're expected to be UTF-8 encoded (lowercase + NFKC). important, don't skip that.

Parameters

  • fname β€” name of the PSL file πŸ”₯

Returns

  • pointer to a PSL context, or NULL on failure 😭

Since: 0.1


🌟 psl_load_fp ()

psl_ctx_t *
psl_load_fp (FILE *fp);

same energy as above but it loads the public suffixes straight from a FILE pointer instead of a filename. also, when you're done, call psl_free() to release everything it grabbed ✨

international suffixes are expected to be UTF-8 encoded (lowercase + NFKC) too.

Parameters

  • fp β€” FILE pointer πŸ“

Returns

  • pointer to a PSL context, or NULL on failure 😭

Since: 0.1


🌟 psl_latest ()

psl_ctx_t *
psl_latest (const char *fname);

this one is the "give me whatever's freshest" girlie πŸ¦‹ it loads the latest available PSL data from either:

  • fname (application specific filename, may be NULL)
  • the location specified during build-time (filename from ./configure --with-psl-distfile)
  • built-in PSL data (generated from ./configure --with-psl-file)
  • the location of the built-in data (filename from ./configure --with-psl-file)

and if none of the above is available? she returns NULL. no data, no vibes πŸ’€

to free the allocated resources, call psl_free() 🫢

Parameters

  • fname β€” name of the PSL file, or NULL 🌸

Returns

  • pointer to a PSL context, or NULL on failure 😭

Since: 0.16


🌟 psl_builtin ()

const psl_ctx_t *
psl_builtin (void);

this gives you the PSL context that got generated and built in at compile-time πŸ‘‘ and the best part? you don't have to free the returned context explicitly. she's built different. literally built in.

the builtin data also contains punycode entries, one for each international domain name ✨

if the generation of built-in data was disabled during compilation, NULL comes back instead 😭 and heads up: when you're using the builtin psl context, you can hand functions like psl_is_public_suffix() either UTF-8 (lowercase + NFKC) or ASCII/ACE (punycode) representations of domains. both are valid, we love a flexible queen πŸ’…

Returns

  • pointer to the built in PSL data, or NULL if this data is not available πŸŽ€

Since: 0.1


🌟 psl_free ()

void
psl_free (psl_ctx_t *psl);

the cleanup function bestie 🧹 this frees the PSL context that you retrieved via psl_load_fp() or psl_load_file(). let her rest.

Parameters

  • psl β€” PSL context pointer 🫢

Since: 0.1


🌟 psl_is_public_suffix ()

int
psl_is_public_suffix (const psl_ctx_t *psl,
                      const char *domain);

this one checks whether domain is a public suffix, using the Mozilla Public Suffix List[2] ✨

for cookie domain checking, go look at psl_is_cookie_domain_acceptable() instead β€” different girl, different job πŸ“

international domain names have to be either in UTF-8 (lowercase + NFKC) or in ASCII/ACE format (punycode). any other encoding will probably give you straight-up wrong return values 😭 so use the helper function psl_str_to_utf8lower() to normalize domain first. do it. love yourself.

psl is a context returned by either psl_load_file(), psl_load_fp() or psl_builtin() πŸ‘‘

Parameters

  • psl β€” PSL context πŸ¦‹
  • domain β€” domain string 🌸

Returns

  • 1 if domain is a public suffix, 0 if not πŸŽ€

Since: 0.1


🌟 psl_is_public_suffix2 ()

int
psl_is_public_suffix2 (const psl_ctx_t *psl,
                       const char *domain,
                       int type);

same as above, she also checks whether domain is a public suffix by the means of the Mozilla Public Suffix List[2] β€” but this version lets you pick the type πŸ’…

type specifies the PSL section where to perform the lookup. valid values are PSL_TYPE_PRIVATE, PSL_TYPE_ICANN, PSL_TYPE_NO_STAR_RULE, and PSL_TYPE_ANY ⭐

PSL_TYPE_NO_STAR_RULE switches off the 'prevailing star rule' (see List[3] under 'Algorithm' 2.). applying this flag means that TLDs that are not explicitly listed in the PSL are not treated as public suffixes. no star, no rule, no exceptions πŸ”₯

international domain names have to be either in UTF-8 (lowercase + NFKC) or in ASCII/ACE format (punycode). other encodings likely result in incorrect return values 😭 use psl_str_to_utf8lower() for normalization on domain.

psl is a context returned by either psl_load_file(), psl_load_fp() or psl_builtin() πŸ‘‘

Parameters

  • psl β€” PSL context πŸ¦‹
  • domain β€” domain string 🌸
  • type β€” domain type ✨

Returns

  • 1 if domain is a public suffix, 0 if not πŸŽ€

Since: 0.1


🌟 psl_unregistrable_domain ()

const char *
psl_unregistrable_domain (const psl_ctx_t *psl,
                          const char *domain);

this one finds the longest public suffix part of domain, again via the Mozilla Public Suffix List[2] πŸ‘‘

international domain names have to be either in UTF-8 (lowercase + NFKC) or in ASCII/ACE format (punycode). other encodings likely result in incorrect return values 😭 use the helper function psl_str_to_utf8lower() for normalization on domain.

psl is a context returned by either psl_load_file(), psl_load_fp() or psl_builtin() 🫢

Parameters

  • psl β€” PSL context πŸ¦‹
  • domain β€” domain string 🌸

Returns

  • pointer to the longest public suffix part of domain, or NULL if domain does not contain a public suffix (or if psl is NULL) πŸ’€

Since: 0.1


🌟 psl_registrable_domain ()

const char *
psl_registrable_domain (const psl_ctx_t *psl,
                        const char *domain);

the twin sister of the one above, except she finds the shortest private suffix part of domain by the means of the Mozilla Public Suffix List[2] 🌈

international domain names have to be either in UTF-8 (lowercase + NFKC) or in ASCII/ACE format (punycode). other encodings likely result in incorrect return values 😭 so use psl_str_to_utf8lower() for normalization on domain. yes, again. it's important.

psl is a context returned by either psl_load_file(), psl_load_fp() or psl_builtin() πŸ‘‘

Parameters

  • psl β€” PSL context πŸ¦‹
  • domain β€” domain string 🌸

Returns

  • pointer to the shortest private suffix part of domain, or NULL if domain does not contain a private suffix (or if psl is NULL) πŸ’€

Since: 0.1


🌟 psl_suffix_count ()

int
psl_suffix_count (const psl_ctx_t *psl);

this one hands you the number of public suffixes maintained by psl. quick note though: the number of exceptions within the Public Suffix List are not included in that count πŸ™ˆ

if the information is not available, the return value is -1 (since 0.19). that's what happens with DAFSA blobs, or if psl is NULL. so if you see a -1, don't panic, it's giving "not available" πŸ’…

Parameters

  • psl β€” PSL context pointer πŸ¦‹

Returns

  • number of public suffixes entries in the PSL context, or -1 if this information is not available 😭

Since: 0.1


🌟 psl_suffix_exception_count ()

int
psl_suffix_exception_count (const psl_ctx_t *psl);

this one returns the number of public suffix exceptions maintained by psl πŸŽ€

if the information is not available, the return value is -1 (since 0.19) β€” same deal as before: that's the case with DAFSA blobs, or if psl is NULL πŸ’€

Parameters

Parameters

  • psl β€” the PSL context pointer, bestie πŸ’…

Returns

The number of public suffix exceptions hangin' out in the PSL context β€” or -1 if that info just isn't available. 😭

Since: 0.1


psl_suffix_wildcard_count() 🌸

int
psl_suffix_wildcard_count (const psl_ctx_t *psl);

okay so this one gives you back the number of public suffix wildcards that psl is keeping track of. πŸ¦‹

And if that information isn't available? The return value is -1 β€” that's been the vibe since 0.19. When does that happen, you ask? DAFSA blobs, or if psl is NULL. That's it, that's the tea. β˜•

Parameters

  • psl β€” PSL context pointer

Returns

Number of public suffix wildcards in the PSL context, or -1 if this information is not available.

Since: 0.10.0


psl_builtin_file_time() ⏰

time_t
psl_builtin_file_time (void);

This one returns the mtime of the Public Suffix List file that's been built in. So like, when was it born. πŸŽ‚

Heads up tho: if the generation of built-in data was disabled during compilation, you just get 0 back. No file time for you. πŸ’€

Returns

time_t value or 0.

Since: 0.1


psl_builtin_sha1sum() πŸ”

const char *
psl_builtin_sha1sum (void);

Gives you the SHA1 checksum of the Public Suffix List file that's been built in. The returned string is in lowercase hex encoding, like this lil guy:

"2af1e9e3044eda0678bb05949d7cca2f769901d8"

If the generation of built-in data was disabled during compilation, you get an empty string instead. rip. πŸ™ˆ

Returns

String containing SHA1 checksum or an empty string.

Since: 0.1


psl_builtin_filename() πŸ“

const char *
psl_builtin_filename (void);

Returns the file name of the Public Suffix List file that's been built in. the name! ✨

And yep, same deal as before β€” if the generation of built-in data was disabled during compilation, it's an empty string for you.

Returns

String containing the PSL file name or an empty string.

Since: 0.1


psl_builtin_outdated() πŸ•°οΈ

int
psl_builtin_outdated (void);

This function checks if the built-in data is older than the file it has been created from. If it is older, it might be a good idea for the application to reload the PSL. The mtime is taken as reference. πŸ‘‘

One lil edge case: if the PSL file does not exist, it's assumed that the built-in data is not outdated. okay? okay. πŸ’…

Returns

1 if the built-in is outdated, 0 otherwise.

Since: 0.10.0


int
psl_is_cookie_domain_acceptable (const psl_ctx_t *psl,
                                 const char *hostname,
                                 const char *cookie_domain);

This helper function checks whether cookie_domain is an acceptable cookie domain value for the request hostname. cookie business πŸͺ

For international domain names, both hostname and cookie_domain have to be either in UTF-8 (lowercase + NFKC) or in ASCII/ACE (punycode) format. Other encodings, or mixing UTF-8 and punycode, likely result in incorrect return values. ⚠️

Use helper function psl_str_to_utf8lower() for normalization of hostname and cookie_domain. So like, do that first bestie.

Hint for Windows users: please make sure the calling application has called WSAStartup() before calling psl_is_cookie_domain_acceptable(). πŸͺŸ

Examples:

  1. Cookie domain 'example.com' would be acceptable for hostname 'www.example.com', but '.com' or 'com' would NOT be acceptable since 'com' is a public suffix.
  2. Cookie domain 'his.name' would be acceptable for hostname 'remember.his.name', but NOT for 'forgot.his.name' since 'forgot.his.name' is a public suffix.

Parameters

  • psl β€” PSL context pointer
  • hostname β€” the request hostname.
  • cookie_domain β€” the domain value from a cookie

Returns

1 if acceptable, 0 if not acceptable.

Since: 0.1


psl_dist_filename() πŸ—‚οΈ

const char *
psl_dist_filename (void);

This function returns the file name of the distribution/system PSL data file. This file will be considered by psl_latest(). πŸ‘€

So basically: return the filename that is set by ./configure --with-psl-distfile, or an empty string. Simple as. πŸ’…

Returns

String containing a PSL file name or an empty string.

Since: 0.16


psl_get_version() 🏷️

const char *
psl_get_version (void);

Get libpsl version. That's literally it, that's the whole function. iconic. πŸ‘‘

Returns

String containing version of libpsl.

Since: 0.2.5


psl_check_version_number() βœ…

int
psl_check_version_number (int version);

Check the given version number is at minimum the current library version number. The version number must be a hexadecimal number like 0x000a01 (V0.10.1). Don't forget that. πŸ”’

Parameters

  • version β€” version number (hex) to check against.

Returns

Returns the library version number if the given version number is at least the version of the library, else return 0; if the argument is 0, the function returns the library version number without performing a check.

Since: 0.11.0


psl_str_to_utf8lower() πŸ¦‹

psl_error_t
psl_str_to_utf8lower (const char *str,
                      const char *encoding,
                      const char *locale,
                      char **lower);

This helper function converts a string to UTF-8 lowercase + NFKC representation. Lowercase + NFKC UTF-8 is needed as input to the domain checking functions, so this is genuinely the glow-up step before the main event. ✨

Important: lower stays unchanged on error. And when returning PSL_SUCCESS, the return value lower must be freed after usage. don't forget to free it bestie I'm begging 😭

Parameters

  • str β€” string to convert
  • encoding β€” charset encoding of str, e.g. 'iso-8859-1' or NULL
  • locale β€” locale of str for to lowercase conversion, e.g. 'de' or NULL
  • lower β€” return value containing the converted string

Returns

A psl_error_t value.

  • PSL_SUCCESS: Success
  • PSL_ERR_INVALID_ARG: str is a NULL value.
  • PSL_ERR_CONVERTER: Failed to open the unicode converter with name encoding
  • PSL_ERR_TO_UTF16: Failed to convert str to unicode
  • PSL_ERR_TO_LOWER: Failed to convert unicode to lowercase
  • PSL_ERR_TO_UTF8: Failed to convert unicode to UTF-8
  • PSL_ERR_NO_MEM: Failed to allocate memory

Since: 0.4


psl_free_string() 🧹

void
psl_free_string (char *str);

This function free()'s the memory allocated by psl_str_to_utf8lower() when returning a lowercase string. cleanup era 🌿

Parameters

  • str β€” pointer to lowercase string returned by psl_str_to_utf8lower()

Since: 0.19


πŸŽ€ TYPES AND VALUES πŸŽ€

PSL_API

#  define PSL_API __attribute__ ((__visibility__("default")))

PSL_VERSION

#define PSL_VERSION "0.23.3"

PSL_VERSION_MAJOR

#define PSL_VERSION_MAJOR 0

PSL_VERSION_MINOR

#define PSL_VERSION_MINOR 23

PSL_VERSION_NUMBER

#define PSL_VERSION_NUMBER 0x001703

PSL_VERSION_PATCH

#define PSL_VERSION_PATCH 3

PSL_TYPE_ICANN

#define PSL_TYPE_ICANN        (1<<0)

PSL_TYPE_PRIVATE

#define PSL_TYPE_PRIVATE      (1<<1)

PSL_TYPE_NO_STAR_RULE

#define PSL_TYPE_NO_STAR_RULE (1<<2)

PSL_TYPE_ANY

#define PSL_TYPE_ANY          (PSL_TYPE_ICANN | PSL_TYPE_PRIVATE)

enum psl_error_t

Return codes for PSL functions. Negative return codes mean failure. Positive values are reserved for non-error return codes. πŸ“‰

Members

  • PSL_SUCCESS β€” Successful return.
  • PSL_ERR_INVALID_ARG β€” Invalid argument.
  • PSL_ERR_CONVERTER β€” Failed to open libicu utf-16 converter.
  • PSL_ERR_TO_UTF16 β€” Failed to convert to utf-16.
  • PSL_ERR_TO_LOWER β€” Failed to convert utf-16 to lowercase.
  • PSL_ERR_TO_UTF8 β€” Failed to convert utf-16 to utf-8.
  • PSL_ERR_NO_MEM β€” Failed to allocate memory.

psl_ctx_t

typedef struct psl_ctx_st psl_ctx_t;

✨ NOTES ✨

okay bestie, before you go, here's the lil stack of receipts πŸ“Ž β€” the source material, the links, the whole ~vibe~. Every time the page says "see note 1" or whatever, this is where it's pointing. no cap. πŸ’…

  1. Public Suffix List β€” the og source of truth: https://publicsuffix.org/
  2. Mozilla Public Suffix List β€” yeah bestie, same URL, she's iconic like that: https://publicsuffix.org
  3. List β€” the actual list itself, go look at it, it's giving: https://publicsuffix.org/list

and that's the whole page, bestie!! πŸŽ€ go forth, parse your publicsuffixes, be the main character of your own hostname resolution. πŸ¦‹

this was LIBPSL Library, dated 08/17/2026 β€” yes, the date is in the future, don't think about it too hard, she's timeless πŸ’œ

mwah πŸ’– stay slay, stay suffixing ✨

πŸ“¦ where this page comes from