The idea of this library started out on the IRC channel, in a discussion on how to best help boost the community of software developers working with things related to CC - mostly the metadata format.
Basically, the idea is to write a portable C library that manages metadata for CC licenses, and a bunch of other licenses of interest to the community.
The library will produce licensing information based on the specifications of calling libraries and programs. In addition to generating text for specific licenses, it will also allow an application to enumerate which licenses are currently available and provide descriptive text for each license, and for license features. It should also provide an easy way to specify "verify at" URLs.
The benefit of this library is that applications linking to it can correctly offer licensing choices, and these choices can be transparently updated through package managers as license versions are updated. Human readable descriptions will also be internationalized, preferably using the same .po files used by the CC web site. Hence liblicense will take advantage of package updating and i18n systems to allow applications to always provide current and correct licensing choices and license text.
Part of the project is also to provide wrappers for the library for other languages, and to help external developers add metadata support to their projects. A good start will probably be to wrap the library for Python, and use it for ccpublisher.
We will also integrate a module system so that libraries can be used to embed and extract metadata in/from common formats.
As liblicense itself deals only with text strings, we can also make GUI libraries to provide dialogs which present these strings to the user in desktop or web applications. This layering ensures that such dialogs present consistent licensing choices.
Once you are done with the library, it is important to call the ll_stop function. This ensures that library resources are free()ed, but more importantly it ensures that caches that need to be have been flushed.
For example, the Sampling Plus license URI looks like this: http://creativecommons.org/licenses/sampling+/1.0/
The license -a command uses code very similar to the following to list all of the available licenses:
#include <liblicense.h> int main (int argc, char **argv) { ll_uri_t *licenses; int i; licenses = ll_get_licenses (NULL); i = 0; while (licenses[i] != NULL) { printf ("%s - %s\n", ll_get_first(ll_get_attribute(licenses[i], LL_NAME, false)), licenses[i]); i++; } ll_free_list (licenses); ll_stop (); return 0; }
The LL_NAME, attribute used to obtain a human-friendly license name. You can not pass a human-friendly name to any of the functions which expect a license URI, they simply will not work. You will have to use ll_get_licenses and walk the list to translate a human-friendly name into a license URI.
There is some logic behind all of this: the human-fiendly names are internationalized, and will be appropriately translated for the current locale. This means the human-fiendly names are not constant from one country to the next, but the license URIs are the same the world over.
#include <liblicense.h> #include <stdio.h> int main (int argc, char **argv) { ll_uri_t uri; ll_init (); uri = ll_read (argv[1], LL_LICENSE); if (uri == NULL) printf ("No license found\n"); else printf ("%s\n", uri); ll_stop (); return 0; }
Some file formats are capable of holding a license within their other application data. For example, PNG files have optional text comment blocks, and the license data could be stored in them. For formats which cannot carry license data, is is also possible to a have a companion ".xmp" license file. The ll_read function checks for both possibilities.
void print_license_info (ll_uri_t uri) { char **attrs, **attr; char *string; ll_version_t version; ll_juris_t juris; int i; printf ("License URI: %s\n", uri); string = ll_get_first(ll_get_attribute(uri, LL_NAME, false)); printf ("Name: %s\n", string); free (string); version = ll_get_version (uri); printf ("Version: "); if (version) { for (i = 1; i <= version[0]; ++i) { if (i != 1) printf ("."); printf ("%d", version[i]); } printf ("\n"); free (version); } juris = ll_get_first(ll_get_attribute(uri, LL_JURISDICTION, false)); if (juris) { string = ll_jurisdiction_name (juris); printf ("Jurisdiction: %s (%s)\n", string, juris); free (string); free (juris); } printf ("Rights:\n"); attrs = ll_get_attribute(uri, LL_PERMITS, false); if (*attrs) { printf (" Permits:\n"); for (attr = attrs; *attr; ++attr) { printf (" %s\n", *attr); } } ll_free_list (attrs); attrs = ll_get_attribute(uri, LL_REQUIRES, false); if (*attrs) { printf (" Requires:\n"); for (attr = attrs; *attr; ++attr) { printf (" %s\n", *attr); } } ll_free_list (attrs); attrs = ll_get_attribute(uri, LL_PROHIBITS, false); if (*attrs) { printf (" Prohibits:\n"); for (attr = attrs; *attr; ++attr) { printf (" %s\n", *attr); } } ll_free_list (attrs); }
When you actually compile and run this code, you will see that once again there are URIs for each of the rights, rather than simple strings.
The above code is a shortened version of the ll_license_print_info function, which you may prefer to use for consistency.
#include <liblicense.h> #include <stdio.h> int main (int argc, char **argv) { ll_uri_t uri; ll_init (); uri = ll_read (argv[1], LL_LICENSE); if (uri == 0) printf ("No license found\n"); else ll_license_print_info (uri); ll_stop (); return 0;
And, as you can see, the amount of code you need to write is much smaller, as well.
We have already seen the LL_LICENSE property you can pass to have ll_read(). The other supported properties are:
To use them, just pass them to ll_read() like you did with LL_LICENSE. Note that ll_write() also accepts these arguments in a similar way.
#include <liblicense.h> int main (int argc, char **argv) { ll_init (); ll_print_module_info (); ll_stop (); return 0; }
The results are printed on the standard output. (This section needs to be expanded for folks who need pick lists for GUIs._