Sqids (pronounced "squids") is a small library that lets you generate YouTube-looking IDs from numbers. It's good for link shortening, fast & URL-safe ID generation and decoding back into numbers for quicker database lookups.
The library is built using GNU Autotools.
./bootstrap
./configure
make
The library includes several blocklists that are enabled and built by default.
You have the option to build it without them by passing --disable-default-blocklist
to configure
.
Unlike Hashids, Sqids relies heavily on dynamic memory allocation.
You can still override the memory management functions if needed, by reassigning sqids_mem_alloc
/sqids_mem_free
.
Sqids defines a thread-safe sqids_errno
with the following possible values:
Value | Description |
---|---|
SQIDS_ERR_ALLOC |
Memory allocation failed. Generally this means errno is ENOMEM . |
SQIDS_ERR_ALPHABET |
Alphabet is too short. |
SQIDS_ERR_MAX_RETRIES |
Max encoding retries reached. |
SQIDS_ERR_INVALID |
Hash contains invalid characters. |
SQIDS_ERR_OVERFLOW |
Integer overflow. |
Keep in mind that you should first test the function result and then inspect sqids_errno
- if a function succeeds, sqids_errno
is left untouched.
sqids_t *
sqids_new(char *alphabet, int min_len, sqids_bl_t *blocklist)
Sqids structure constructor.
If you pass NULL
null as the alphabet, SQIDS_DEFAULT_ALPHABET
will be used.
A NULL
blocklist will result in no blocklist at all.
See the blocklist API below for further information.
The returned structure should be freed using sqids_free
.
In case of failure, NULL
is returned and sqids_errno
is set accordingly.
/* free a sqids structure */
void
sqids_free(sqids_t *sqids)
Sqids structure destructor.
Deallocates the Sqids structure including the alphabet and the blocklist, if present.
void
sqids_shuffle(char *alphabet)
Consistent shuffle.
Chances are you won't be using this anywhere outside Sqids.
char *
sqids_encode(sqids_t *sqids, unsigned int num_cnt, unsigned long long *nums)
Encode function.
Encodes an array of numbers to a string hash.
In case of failure, NULL
is returned and sqids_errno
is set accordingly.
char *
sqids_vencode(sqids_t *sqids, unsigned int num_cnt, ...)
Variadic version of sqids_encode
.
int
sqids_num_cnt(sqids_t *sqids, char *s)
Number counting function.
Returns the count of numbers in an hash.
Keep in mind that this function can return 0
as empty strings are not considered errors.
In case of failure, -1
is returned and sqids_errno
is set accordingly.
int
sqids_decode(sqids_t *sqids, char *s, unsigned long long *nums, unsigned int num_max)
Decode function.
Decodes a hash back to numbers.
Keep in mind that this function can return 0
as empty strings are not considered errors.
Result is the count of numbers decoded in the hash.
In case of failure, -1
is returned and sqids_errno
is set accordingly.
sqids_bl_t *
sqids_bl_new(int (*match_func)(char *, char *))
Blocklist constructor.
Returns a new empty blocklist, which itself is a doubly linked list.
If you pass NULL
as match_func
, it will default to sqids_bl_match
.
In case of failure, NULL
is returned and sqids_errno
is set accordingly.
void
sqids_bl_free(sqids_bl_t *bl)
Blocklist destructor.
Frees the blocklist and all its data.
sqids_bl_node_t *
sqids_bl_add_tail(sqids_bl_t *bl, char *s)
Adds a word to the end of the blocklist.
Result is a pointer to the new blocklist node.
In case of failure, NULL
is returned and sqids_errno
is set accordingly.
sqids_bl_node_t *
sqids_bl_add_head(sqids_bl_t *bl, char *s)
Adds a word to the beginning of the blocklist.
Result is a pointer to the new blocklist node.
In case of failure, NULL
is returned and sqids_errno
is set accordingly.
sqids_bl_node_t *
sqids_bl_find(sqids_bl_t *bl, char *s)
Tests if a string matches any of the bad words in the blocklist.
Result is pointer to the matching blocklist node, or NULL
if no match is found.
int
sqids_bl_match(char *s, char *bad_word)
Default blocklist match function.
Tests if a string matches a bad word.
Result is 1
in case of a match, 0
otherwise.
sqids_bl_t *
sqids_bl_list_LANG(int (*match_func)(char *, char *))
Will either return the combined blocklist of a language-specific one.
If you pass NULL
as match_func
, sqids_bl_match
will be used as default.
In case of failure, NULL
is returned and sqids_errno
is set accordingly.
Function | Description |
---|---|
sqids_bl_list_all |
The default blocklist, contains all language-specific blocklists combined. |
sqids_bl_list_de |
German blocklist. |
sqids_bl_list_en |
English blocklist. |
sqids_bl_list_es |
Spanish blocklist. |
sqids_bl_list_fr |
French blocklist. |
sqids_bl_list_hi |
Hindi blocklist. |
sqids_bl_list_it |
Italian blocklist. |
sqids_bl_list_pt |
Portuguese blocklist. |
A command-line utility is provided so one can easily encode/decode hashes and experiment with the library.
Simple encode & decode:
#include <sqids.h>
sqids_t *sqids = sqids_new(SQIDS_DEFAULT_ALPHABET, 0, sqids_bl_list_all(NULL));
unsigned long long nums[] = {1, 2, 3};
char *hash = sqids_encode(sqids, 3, nums); // => "86Rf07"
sqids_decode(sqids, hash, nums, 3); // => 3
sqids_mem_free(hash);
sqids_free(sqids);
Enforce a minimum length:
#include <sqids.h>
sqids_t *sqids = sqids_new(SQIDS_DEFAULT_ALPHABET, 10, sqids_bl_list_all(NULL));
unsigned long long nums[] = {1, 2, 3};
char *hash = sqids_encode(sqids, 3, nums); // => "86Rf07xd4z"
sqids_decode(sqids, hash, nums, 3); // => 3
sqids_mem_free(hash);
sqids_free(sqids);
Using a custom alphabet will produce different results:
#include <sqids.h>
sqids_t *sqids = sqids_new("FxnXM1kBN6cuhsAvjW3Co7l2RePyY8DwaU04Tzt9fHQrqSVKdpimLGIJOgb5ZE", 0, sqids_bl_list_all(NULL));
unsigned long long nums[] = {1, 2, 3};
char *hash = sqids_encode(sqids, 3, nums); // => "B4aajs"
sqids_decode(sqids, hash, nums, 3); // => 3
sqids_mem_free(hash);
sqids_free(sqids);
Custom blocklist is just as simple:
#include <sqids.h>
sqids_bl_t *bl = sqids_bl_new(NULL);
sqids_bl_add_tail(bl, "86Rf07");
sqids_t *sqids = sqids_new(SQIDS_DEFAULT_ALPHABET, 0, bl);
unsigned long long nums[] = {1, 2, 3};
char *hash = sqids_encode(sqids, 3, nums); // => "se8ojk"
sqids_decode(sqids, hash, nums, 3); // => 3
sqids_mem_free(hash);
sqids_free(sqids);
For a more thorough example of the API, take a look at src/main.c.