Getting started

This short guide explains how to get started.

First example - cat.c

A simple cat program, with minimal error checking. It simply outputs everything in a file to stdout.

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#include <lfp/lfp.h>

int main(int args, char** argv) {
    if (args < 2) {
        fputs("usage: cat FILE", stderr);
        exit(EXIT_FAILURE);
    }

    /*
     * Open the file the standard way
     */
    FILE* fp = fopen(argv[1], "rb");
    if (!fp) {
        perror("unable to open file");
        exit(EXIT_FAILURE);
    }

    /*
     * Give the file to the cfile protocol, which takes
     * ownership of the file handle
     */
    lfp_protocol* cfile = lfp_cfile(fp);
    if (!cfile) {
        // OS will clean up fp
        exit(EXIT_FAILURE);
    }

    /*
     * Read data in chunks of 1024 bytes at the time
     */
    unsigned char buf[1024];
    for (;;) {
        int64_t nread;
        int err = lfp_readinto(cfile, buf, sizeof(buf), &nread);
        switch (err) {
            case LFP_OK:
            case LFP_OKINCOMPLETE:
            case LFP_EOF:
                /*
                 * Reading was a success
                 */
                break;

            default:
                /*
                 * Reading failed, maybe something is wrong with
                 * the device. Just print some simple diagnostic
                 * from errno and abort.
                 */
                perror(lfp_errormsg(cfile));
                lfp_close(cfile);
                exit(EXIT_FAILURE);
        }

        /*
         * Output the freshly-read data to stdout
         */
        fwrite(buf, 1, nread, stdout);

        /*
         * Incomplete read - since this is a file, not a pipe, it is
         * end-of-file, so exit
         */
        if (err == LFP_EOF) {
            lfp_close(cfile);
            return EXIT_SUCCESS;
        }
    }
}

Building with cmake

Layered file protocols provides a cmake config, so add this to your CMakeLists.txt:

find_package(lfp REQUIRED)

add_library(app app.c)
target_link_libraries(app lfp::lfp)

Second example - tif-cat.c

Let us extend the cat program, by adding support for tape image format (TIF) files.

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#include <lfp/lfp.h>
#include <lfp/tapeimage.h>

int main(int args, char** argv) {
    if (args < 2) {
        fputs("usage: tif-cat FILE", stderr);
        exit(EXIT_FAILURE);
    }

    FILE* fp = fopen(argv[1], "rb");
    if (!fp) {
        perror("unable to open file");
        exit(EXIT_FAILURE);
    }

    lfp_protocol* cfile = lfp_cfile(fp);
    if (!cfile) exit(EXIT_FAILURE);

    lfp_protocol* tfile = lfp_tapeimage_open(cfile);
    if (!tfile) {
        lfp_close(cfile);
        exit(EXIT_FAILURE);
    }

    /*
     * This is identical to cat.c, but with tfile instead of cfile
     */
    unsigned char buf[1024];
    for (;;) {
        int64_t nread;
        int err = lfp_readinto(tfile, buf, sizeof(buf), &nread);
        switch (err) {
            case LFP_OK:
            case LFP_OKINCOMPLETE:
            case LFP_EOF:
                break;

            case LFP_UNEXPECTED_EOF:
                /*
                 * Read all available data, but the protocol expected there to
                 * be more data than it was.
                 */
                perror(lfp_errormsg(tfile));

            default:
                perror(lfp_errormsg(tfile));
                lfp_close(tfile);
                exit(EXIT_FAILURE);
        }

        fwrite(buf, 1, nread, stdout);

        if (err == LFP_EOF) {
            lfp_close(tfile);
            return EXIT_SUCCESS;
        }
    }
}

This program is almost identical to cat.c, but the the tapeimage protocol is layered over the cfile. Notice how the main loop is unmodified, yet the program now outputs the contents of a file sans the tape marks. In fact, this is a pretty useful tool on its own for stripping tape marks from files.