Add LID capability to oonf_layer2 and l2config subsystem
[oonf.git] / src / libcommon / template.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4  * Copyright (c) 2004-2015, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 /**
43  * @file
44  */
45
46 #include <stdio.h>
47 #include <stdlib.h>
48
49 #include <oonf/oonf.h>
50 #include <oonf/libcommon/autobuf.h>
51 #include <oonf/libcommon/string.h>
52 #include <oonf/libcommon/template.h>
53
54 static struct abuf_template_data_entry *_find_template(
55   struct abuf_template_data *set, size_t set_count, const char *txt, size_t txtLength);
56
57 /**
58  * Initialize an index table for a template engine.
59  * Each usage of a key in the format has to be %key%.
60  * The existing keys (start, end, key-number) will be recorded
61  * in the integer array the user provided, so the template
62  * engine can replace them with the values later.
63  *
64  * @param storage pointer to template storage
65  * @param data array of key/value pairs for the template engine
66  * @param data_count number of keys
67  * @param format format string of the template
68  */
69 void
70 abuf_template_init_ext(
71   struct abuf_template_storage *storage, struct abuf_template_data *data, size_t data_count, const char *format) {
72   /* helper string for 'just one tab between keys' */
73   static const char default_format[] = "\t";
74
75   struct abuf_template_data_entry *d;
76   bool no_open_format = true;
77   bool escape = false;
78   size_t start = 0;
79   size_t pos = 0;
80   size_t i, j;
81
82   memset(storage, 0, sizeof(*storage));
83
84   if (!format) {
85     /* generate default format, just tab between each value */
86     storage->format = default_format;
87
88     storage->count = 0;
89
90     for (j = 0; j < data_count; j++) {
91       for (i = 0; i < data[j].count; i++) {
92         storage->indices[storage->count].start = 1;
93         storage->indices[storage->count].end = 0;
94         storage->indices[storage->count].data = &data[j].data[i];
95         storage->count++;
96       }
97     }
98
99     if (storage->count) {
100       storage->indices[0].start = 0;
101       storage->indices[storage->count - 1].end = 1;
102     }
103     return;
104   }
105
106   storage->format = format;
107   while (format[pos]) {
108     if (!escape && format[pos] == '%') {
109       if (no_open_format) {
110         start = pos++;
111         no_open_format = false;
112         continue;
113       }
114       if (pos - start > 1) {
115         d = _find_template(data, data_count, &format[start + 1], pos - start - 1);
116         if (d) {
117           storage->indices[storage->count].start = start;
118           storage->indices[storage->count].end = pos + 1;
119           storage->indices[storage->count].data = d;
120
121           storage->count++;
122         }
123       }
124       no_open_format = true;
125     }
126     else if (format[pos] == '\\') {
127       /* handle "\\" and "\%" in text */
128       escape = !escape;
129     }
130     else {
131       escape = false;
132     }
133
134     pos++;
135   }
136 }
137
138 /**
139  * Append the result of a template engine into an autobuffer.
140  * Each usage of a key will be replaced with the corresponding
141  * value.
142  * @param out pointer to autobuf object
143  * @param storage pointer to template storage object, which will be filled by
144  *   this function
145  * @param keys true if the engine should leave the keys in there,
146  *   false to insert the values.
147  */
148 void
149 abuf_add_template(struct autobuf *out, struct abuf_template_storage *storage, bool keys) {
150   struct abuf_template_storage_entry *entry;
151   size_t i, last = 0;
152   const char *value;
153
154   for (i = 0; i < storage->count; i++) {
155     entry = &storage->indices[i];
156
157     /* copy prefix text */
158     if (last < entry->start) {
159       abuf_memcpy(out, &storage->format[last], entry->start - last);
160     }
161
162     if (keys) {
163       value = entry->data->key;
164     }
165     else {
166       value = entry->data->value;
167     }
168     if (value) {
169       abuf_puts(out, value);
170     }
171     last = entry->end;
172   }
173
174   if (last < strlen(storage->format)) {
175     abuf_puts(out, &storage->format[last]);
176   }
177 }
178
179 /**
180  * Find the template data corresponding to a key
181  * @param set pointer to template data array
182  * @param set_count number of template data entries in array
183  * @param txt pointer to text to search in
184  * @param txtLength length of text to search in
185  * @return pointer to corresponding template data, NULL if not found
186  */
187 static struct abuf_template_data_entry *
188 _find_template(struct abuf_template_data *set, size_t set_count, const char *txt, size_t txtLength) {
189   size_t i, j;
190
191   for (j = 0; j < set_count; j++) {
192     for (i = 0; i < set[j].count; i++) {
193       const char *key;
194
195       key = set[j].data[i].key;
196       if (strncmp(key, txt, txtLength) == 0 && key[txtLength] == 0) {
197         return &set[j].data[i];
198       }
199     }
200   }
201   return NULL;
202 }