aboutsummaryrefslogtreecommitdiff
path: root/docs/devel.md
blob: a288ef5cde157ee8e9dad6a8c830b68fc742a64a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# Developing

# Using the tpl_* functions 

```c
#include <stdio.h>      // for fprintf, free, puts
#include <stdlib.h>     // for strdup
#include "template.h"   // for tpl_free, tpl_register, tpl_render

int main(int argc, char *argv[]) {
    char *value = strdup("the value");
    tpl_register("my_data", &value);
    char *rendered = tpl_render("I am showing you {{ my_data }}.");
    if (rendered) {
        puts(rendered);
        free(rendered);
    } else {
        fprintf()
    }
    tpl_free();
}
```

`tpl_register` accepts an address to a heap-allocated pointer of type `char`. One cannot pass the address of a stack-allocated character string, because chances are reasonably high that your C compiler detect this condition and throw an _incompatible pointer_ error. You may, however, register a pointer to a string that has been allocated on the stack (see example).

```c
// Invalid (stack)
char value[255];

// Invalid (stack)
char value[] = "the value";

// Valid (pointer to stack)
char value_s[] = "the value";
char *value = value_s;

// Valid (heap)
char *value = calloc(255, sizeof(*value));
strcpy(value, "the value");

// Valid (heap)
char *value = strdup("the value");
```

The `tpl_render` function parses an input string and replaces any references encapsulated by double curly braces (`{{}}`) with the _current_ value of a registered template variable. Empty references and undefined variables are ignored, however whitespace surrounding the reference will be preserved in the result. If an unrecoverable error occurs while rendering this function returns `NULL`.

The following illustrates this effect:
```c
char *abc = strdup("ABC");
tpl_register("abc", &abc);
char *rendered = tpl_render("{{}} {{ undefined_var }} I know my {{ abc }}'s!");
// Result: "  I know my ABC's!"
//          ^^ whitespace
free(rendered);
tpl_free();
```

One should consider using the `normalize_space` function to remove undesired whitespace from the rendered output.

```c
#include <stdio.h> // for fprintf, stderr
#include "str.h"   // for normalize_space

// ...
char *rendered = tpl_render("{{}} {{ undefined_var }} I know my {{ abc }}'s!");
if (rendered) {
    // Remove leading, trailing, and repeated whitespace
    normalize_space(rendered);
} else {
    fprintf(stderr, "unable to render input string\n");
    exit(1);
}
free(rendered);
tpl_free();
// Result: "I know my ABC's!"
```

Most calls to `tpl_render` use data read from a file. The examples below should clarify how to achieve this.

Template file: **index.html.in**

```html
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>{{ site_title }}</title>
    </head>
    <body>
        {{ site_body_text }}
        <br/>
        {{ site_footer }}
    </body>
</html>
```

- Using the standard library

```c
#include <stdio.h>      // for fgets
#include <string.h>
#include <stdlib.h>
#include "template.h"   // for tpl_render

struct Site {
    char *title;
    char *body;
    char *footer;
} site;

void site_setup_template() {
    tpl_register("site_title", &site.title);
    tpl_register("site_body", &site.body);
    tpl_register("site_footer", &site.footer);
}

void site_setup_data() {
    site.title = strdup("My static site");
    site.body = strdup("This is the body.");
    site.footer = strdup("Generated with tpl_render()");
}

int main(int argc, char *argv[]) {
    char line[BUFSIZ] = {0};
    char *filename = argv[1];
    FILE *fp = fopen(filename, "r");
    if (!fp) {
        perror(filename);
        exit(1);
    }
    
    while (fgets(line, sizeof(line) - 1, fp) != NULL) {
        char *rendered = tpl_render(line);
        if (rendered) {
            normalize_space(rendered);
            printf("%s", rendered);
        }
    }
    fclose(fp);
}
```

- Using file_readlines

```c

#include "util.h"
```