11.3 Using program resources

A resource is very similar to a file. Resources, however, can be represented in two different formats: on files, as well as part of the resource archive of a saved state (see qsave_program/2).

A resource has a name and a class. The source data of the resource is a file. Resources are declared by declaring the predicate resource/3. They are accessed using the predicate open_resource/3.

Before going into details, let us start with an example. Short texts can easily be expressed in Prolog source code, but long texts are cumbersome. Assume our application defines a command `help' that prints a helptext to the screen. We put the content of the helptext into a file called help.txt. The following code implements our help command such that help.txt is incorporated into the runtime executable.

resource(help, text, 'help.txt').

help :-
        open_resource(help, text, In),
        call_cleanup(copy_stream_data(In, user_output),
                     close(In)).

The predicate help/0 opens the resource as a Prolog stream. If we are executing this from the development environment, this will actually return a stream to the file help.txt itself. When executed from the saved state, the stream will actually be a stream opened on the program resource file, taking care of the offset and length of the resource.

11.3.1 Resource manipulation predicates

resource(+Name, +Class, +FileSpec)
This predicate is defined as a dynamic predicate in the module user. Clauses for it may be defined in any module, including the user module. Name is the name of the resource (an atom). A resource name may contain any character, except for $ and :, which are reserved for internal usage by the resource library. Class describes the kind of object stored in the resource. In the current implementation, it is just an atom. FileSpec is a file specification that may exploit file_search_path/2 (see absolute_file_name/2).

Normally, resources are defined as unit clauses (facts), but the definition of this predicate also allows for rules. For proper generation of the saved state, it must be possible to enumerate the available resources by calling this predicate with all its arguments unbound.

Dynamic rules are useful to turn all files in a certain directory into resources, without specifying a resource for each file. For example, assume the file_search_path/2 icons refers to the resource directory containing icon files. The following definition makes all these images available as resources:

resource(Name, image, icons(XpmName)) :-
        atom(Name), !,
        file_name_extension(Name, xpm, XpmName).
resource(Name, image, XpmFile) :-
        var(Name),
        absolute_file_name(icons(.), [type(directory)], Dir)
        concat(Dir, '/*.xpm', Pattern),
        expand_file_name(Pattern, XpmFiles),
        member(XpmFile, XpmFiles).
open_resource(+Name, ?Class, -Stream)
Opens the resource specified by Name and Class. If the latter is a variable, it will be unified to the class of the first resource found that has the specified Name. If successful, Stream becomes a handle to a binary input stream, providing access to the content of the resource.

The predicate open_resource/3 first checks resource/3. When successful it will open the returned resource source file. Otherwise it will look in the program's resource database. When creating a saved state, the system normally saves the resource contents into the resource archive, but does not save the resource clauses.

This way, the development environment uses the files (and modifications) to the resource/3 declarations and/or files containing resource info, thus immediately affecting the running environment, while the runtime system quickly accesses the system resources.

11.3.2 The swipl-rc program

The utility program swipl-rc can be used to examine and manipulate the contents of a SWI-Prolog resource file. The options are inspired by the Unix ar program. The basic command is:

% swipl-rc option resource-file member ...

The options are described below.

l
List contents of the archive.
x
Extract named (or all) members of the archive into the current directory.
a
Add files to the archive. If the archive already contains a member with the same name, the contents are replaced. Anywhere in the sequence of members, the options --class=class and --encoding=encoding may appear. They affect the class and encoding of subsequent files. The initial class is data and encoding none.
d
Delete named members from the archive.

This command is also described in the pl(1) Unix manual page.