Skip to content
it4e edited this page May 1, 2017 · 19 revisions

This will be an in depth tutorial on the structure of CHL web applications, and a walk through on how to get started and how to use the CHL API properly. The tutorial is divided into various sections, which you can have a look on here: contents.

The first section is a quick introduction to let you know what CHL is all about and what it can do for you. The next section will go through the whole structure of CHL, teaching you how to cooperate different types of files to end up with a good working and good structured CHL web application. We will then dwell deeper and deeper into the CHL API for your pleasure.

Before you start reading this tutorial, make sure you have CHL installed and that everything is properly set up. Setting up CHL.

See FastCGI if you want to use CHL with FastCGI. Everything in this tutorial, however, will also work with FastCGI as well, so make sure you do not skip this.

CHL, short for C Hypertext Library, is a library written in C to be used to write web applications. If you have ever used a language designed for creating server-side webscripts, PHP or ASP for instance, you will feel quite familiar with CHL, since CHL is used for the exact same purpose. The only difference, however, is that CHL provides you with the ability to write those Web applications in pure C, instead of having to learn a new language. Many people, including myself, also finds great joy in writing code in C, so why not do it for developing Web applications as well?

Just like any other programming language designed for developing web applications, CHL (although a library) provides you with the same features. CHL enables you to easily parse and fetch HTTP data, such as POST and GET. CHL gives you all the functionality you need to create your own headers, including a dedicated API for creating and deleting cookies. CHL also comes shipped with a very special, handcrafted parser and interpreter to give you the ability to execute CHL functions within HTML files, using a very straight-forward syntax. These are only a small number of things that CHL can do for you.

As CHL is open-source, people are able to contribute with their own APIs, plugins and code which means that CHL is constantly upgraded and provided with new features. Do you have an idea for a new CHL function and want to contribute? See contribute.

Web applications written in C must somehow be executed by the Web server, since C is a compiled langauge. To make this possible CHL is based on CGI (Common Gateway Interface), which in short means that the server executes your program and passes it data through environment variables. CHL does all the parsing and handling of CGI in the background, and provides you with some easy to use functions instead.

Curious huh? Feel free to take a look through the source code, or maybe even contribute yourself? (although I strongly recommend you read this tutorial first).

CHL web applications are built up of three different types of "files". These files are put together and cooperate in a very straight-forward, non-complicated way, to form the end application.

The three types of files are:

  • CHL controller file (.chl extension): every page of your web application should consist of exactly one CHL controller file. This file is the final executable when you have successfully compiled all of your source files containing the CHL code of the program. This is the file which is requested by the clients. Of course there is nothing that says you can not split your code into multiple files, but the final executable of all the source files will always be the controller.

  • CHL view file (recommended extension: .vw, although not required): every page of your web application should mostly consist of at least 1 view file. The view files are nothing more than simple HTML files really, with the "small" difference being that they may contain inline CHL code that can be executed by the controller. The view file works as the main HTML document for the web page and a controller may only include one view file at a time.

  • CHL view component file (recommended extension: .vc, again not required): every page of your web application may consist of a variable number of view component files. These files work as a complement to the main view file, and are often included inside the view files themselves. For instance, if you decide you want a fixed header on every page of your application you may put the header HTML code inside a view component file and then include that file in all of the view files.

A typical CHL web application may look something like this.

Controller file: 'main.c' (compiled to 'main.chl')

#include <chl/chl.h>

// Function to import component view file, called by view
void import(char * args) {
  // Get argument passed to function called by view
  char * name = chl_next_arg(args);
  
  // Import file: put the contents of [name] in view
  chl_import(name);
}

int main() {
  // Make funtion import available to view
  chl_func_append("import", import);
  
  // Open view 'view.vw'
  chl_view("view.vw");
}

View file: 'view.vw' (called by controller 'main.c')

<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <!-- Call function import, defined in controller -->
    <!-- Put contents of component.vc here -->
    <{ import("component.vc"); }>
  </body>
</html>

View component file: 'component.vc' (called by view 'view.vw')

<p>Hello world!</p>

Compiling and executing 'main.chl', unsurprisingly yields:

<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <!-- Call function import, defined in controller -->
    <!-- Put contents of component.vc here -->
    <p>Hello world!</p>
  </body>
</html>

As you see the line '<{ import("component.vc"); }>' was replaced with '<p>Hello world!</p>', the contents of 'component.vc'.

This should have hopefully given you a clear image of how CHL web applications are structured and made, but if you somehow feel like you did not understand everything there really are no worries. You will grasp this better as we get to the coding.

Compiling a CHL program does not differ from compiling with any other library in C. CHL uses the shared library 'libchl.so', which can be found in '/usr/lib/chl/libchl.so', and should be linked with the compiler everytime you compile and link a source file. As your code may also contain functions defined in libraries other than libchl (CHL plugins dependencies), it is a good idea to include all of the libraries in /usr/lib/chl.

When compiling and linking with gcc we will use the path '/usr/lib/chl/'* to ensure that gcc knows of all of the libraries. Use the following command to compile your CHL source files:

gcc source_files /usr/lib/chl/*

For instance, if you want to compile the files main.c and funcs.c to the CHL controller file 'index.chl':

gcc main.c funcs.c /usr/lib/chl/* -o index.chl

Although, if you are absolutely sure that you will only be using functions defined in libchl, you may as well do this:

gcc main.c funcs.c -lchl -L/usr/lib/chl -o index.chl

alt tag

A good starting program has been the well known ”Hello world”-program for a very good while now. In this tutorial we will follow the same standard and write our own version of the ”Hello world” program. This program will be very simple and you will not see anything too fancy, but do not distrust, writing a ”Hello world” program is a very good step in the right direction.

This program will have a very basic structure for simplicity and to give you a deeper understanding of the underlying implementation of CHL. The program will consist of a standard CHL Controller file, which will output the standard HTTP headers and the text line 'Hello world!'.

Code

#include <chl/chl.h>
#include <stdio.h>

int main() {
  /* Set and print default HTTP headers */
  chl_set_default_headers();
  chl_print_headers();
  
  // Output "Hello world!"
  printf("Hello world!");
}

As you can see the CHL functions are very self-descriptive. First of all we include the standard CHL header chl/chl.h, which contains all of the functions available in the CHL API.

(Note that you can click on the function names)

chl_set_default_headers(): defines the default HTTP headers to make the website work (content-type e.t.c).
chl_print_headers(): prints out the default HTTP headers (and the ones you have set yourself).

printf(): I am sure you know what this line does since it is a standard C function, but the thing to note here however is that every output to your web application should be made to standard output (stdout), just as in any other C program.

Save the file as 'main.c', and compile with the following command:

gcc main.c /usr/lib/chl/* -o index.chl

Make sure the compiled file 'index.chl' is in your web server directory. Type localhost/index.chl in a browser window to open the application.

In your browser window

Hello world!

The usage of views is a great way to split the backend logic from the more abstract frontend. The backend code is put into the CHL Controller File, whereas everything visible is implemented through the view file(s). This concept makes for great code and readability, which are very important factors when working with larger projects.

You shall create one controller file for every page on your site, whereas you may create as many view files per controller as you want. However, only one single view file may be used at once. You import view files using the chl_view() function.

For instance, let's assume you have a page which should have a certain look depending on if the user is logged in or not. The implementation of this in CHL would be to create two view files, one for logged in users (loggedin.vw) and one for standard users (standard.vw). The controller file would then check whether the user is logged in, and import the corresponding view file.

// PSEUDO CODE
if user is logged in
    chl_view("loggedin.vw");
else
    chl_view("standard.vw");

main.c (CHL Controller file)

#include <chl/chl.h>

int main() {
    chl_view("hello.vw"); // Import view hello.vw
    return 0;
}

hello.vw (CHL View file)

<!DOCTYPE html>
<html>
    <head>
    </head>
    <body>
        Hello World!
    </body>
</html>

First of all we create a controller file 'main.c' which imports the view file 'hello.vw'. As you can see, in comparison to our first hello world application, we do not use the functions chl_set_default_headers() and chl_print_headers(), as chl_view() calls these functions for us as standard.

The view file 'hello.vw' is then created, which is nothing really but a plain HTML file.

chl_view(): used to import view files, standard is to call chl_set_default_headers and chl_print_headers.
chl_import(): used to import view files, does not call chl_set_default_headers and chl_print_headers.

Make sure the files are in the same folder and compile with the following command:

gcc main.c /usr/lib/chl/* -o index.chl

Once again, output

Hello World!

One of the things that makes CHL special is that you can execute functions inside of the view files themselves. This makes it a lot easier and a lot more dynamic to output data generated by the controller file.

The syntax for executing CHL functions inside view files is as follows: <{ function(args); }>. The inline opener "<{" marks the start of where the parser should begin, whereas "}>" marks the end. Inside of these markers you utilize the standard function syntax to specify functions for executing.

Note that you may specify multiple functions inside of the same inline block: <{ function1(args); function2(args); }> e.t.c.

The parser does not care about spacing or case. You may put functions on several lines.

CHL provides a set of its own predefined CHL inline functions, which can be used by the programmer directly. These functions can be found in the API.

Here is an example of the standard inline function print(), which outputs a line.

main.c (Controller file)

#include <chl/chl.h>

int main() {
    // Call view file
    chl_view("index.vw");
    return 0;
}

index.vw (View file)

....
<body>
<{ print("Hello"); }>
</body>
....

Output: .... Hello ....

Apart from the standard inline functions, you are also able to create your own functions. The CHL function must be of the following type:

A CHL function may not return anything (void), and must have a char * args as an argument. [args] will then be passed the inline arguments by the parser, if any.

void function(char * args)

To make the function available to the views you must pass it to the function chl_func_append.

void chl_func_append(char * name, void (* function)(char *))

Where [name] is the name with which you want the function to be called from the view files, and [function] is the function itself.

It is always clearer when you see an example of it:

main.c (Controller file)

#include <chl/chl.h>

// Inline function
void print_hello(char * args) {
    printf("Hello");
}

int main() {
    // Make function available
    chl_func_append("print_hello", print_hello);

    // Call view file
    chl_view("index.vw");
    return 0;
}

index.vw (View file)

<body>
    <{ 
        print_hello(); 
        print_hello(); 
        print_hello(); 
        print_hello(); 
    }>
</body>

Output: Hello Hello Hello Hello

Inline functions may also take arguments of their own. The arguments are passed to the [args] variable in a special format that may be parsed by utilizing some of the CHL functions. See the API for all of them.

The most simple one is the function chl_get_args, which has the following declaration:

char chl_get_args(char *(** arguments), char * args);

Where [arguments] is the address of a char ** variable, and [args] is the variable passed by the parser. The function fills the [arguments] array with all of the inline arguments passed to the function. The return value is the number of arguments.

You may access these arguments by index, arguments[0] for first argument, arguments[1] for the second argument and so on.

As always, an example:

main.c (Controller file)

#include <chl/chl.h>

// Inline function to print arguments
void print_args(char * args) {
    char ** arguments; // Arguments array
    char nargs; // Number of arguments
    
    // Fetch arguments
    nargs = chl_get_args(&arguments, args); 

    // Output arguments
    int i;
    for(i = 0; i < nargs; i++)
        printf("%s", arguments[i]);
}

int main() {
    // Make function available
    chl_func_append("print_args", print_args);

    // Call view file
    chl_view("index.vw");
    return 0;
}

index.vw (View file)

<body>
    <{ print_args("You", " are", " a", " noob"); }>
</body>

Output: You are a noob

See also: chl_next_arg(), chl_next_argf(), chl_next_argi()

As CHL is open-source, people are able to contribute with their own APIs, plugins and code which means that CHL is constantly upgraded and provided with new features. Do you have an idea for a new CHL feature and want to contribute?

See contribute.

Setup. API. Tutorial. Examples. FastCGI.

Clone this wiki locally