mustach-tool.c (5048B)
1 /* 2 Author: José Bollo <jobol@nonadev.net> 3 4 https://gitlab.com/jobol/mustach 5 6 SPDX-License-Identifier: ISC 7 */ 8 9 #ifndef _GNU_SOURCE 10 #define _GNU_SOURCE 11 #endif 12 13 #include <stdlib.h> 14 #include <stdio.h> 15 #include <sys/stat.h> 16 #include <unistd.h> 17 #include <fcntl.h> 18 #include <string.h> 19 #include <libgen.h> 20 21 #include "mustach-wrap.h" 22 23 static const size_t BLOCKSIZE = 8192; 24 25 static const char *errors[] = { 26 "??? unreferenced ???", 27 "system", 28 "unexpected end", 29 "empty tag", 30 "tag too long", 31 "bad separators", 32 "too depth", 33 "closing", 34 "bad unescape tag", 35 "invalid interface", 36 "item not found", 37 "partial not found", 38 "undefined tag", 39 "too much template nesting" 40 }; 41 42 static const char *errmsg = 0; 43 static int flags = 0; 44 static FILE *output = 0; 45 46 static void help(char *prog) 47 { 48 char *name = basename(prog); 49 #define STR_INDIR(x) #x 50 #define STR(x) STR_INDIR(x) 51 printf("%s version %s\n", name, STR(VERSION)); 52 #undef STR 53 #undef STR_INDIR 54 printf( 55 "\n" 56 "USAGE:\n" 57 " %s [FLAGS] <json-file> <mustach-templates...>\n" 58 "\n" 59 "FLAGS:\n" 60 " -h, --help Prints help information\n" 61 " -s, --strict Error when a tag is undefined\n" 62 "\n" 63 "ARGS: (if a file is -, read standard input)\n" 64 " <json-file> JSON file with input data\n" 65 " <mustach-templates...> Template files to instantiate\n", 66 name); 67 exit(0); 68 } 69 70 static char *readfile(const char *filename, size_t *length) 71 { 72 int f; 73 struct stat s; 74 char *result; 75 size_t size, pos; 76 ssize_t rc; 77 78 result = NULL; 79 if (filename[0] == '-' && filename[1] == 0) 80 f = dup(0); 81 else 82 f = open(filename, O_RDONLY); 83 if (f < 0) { 84 fprintf(stderr, "Can't open file: %s\n", filename); 85 exit(1); 86 } 87 88 fstat(f, &s); 89 switch (s.st_mode & S_IFMT) { 90 case S_IFREG: 91 size = s.st_size; 92 break; 93 case S_IFSOCK: 94 case S_IFIFO: 95 size = BLOCKSIZE; 96 break; 97 default: 98 fprintf(stderr, "Bad file: %s\n", filename); 99 exit(1); 100 } 101 102 pos = 0; 103 result = malloc(size + 1); 104 do { 105 if (result == NULL) { 106 fprintf(stderr, "Out of memory\n"); 107 exit(1); 108 } 109 rc = read(f, &result[pos], (size - pos) + 1); 110 if (rc < 0) { 111 fprintf(stderr, "Error while reading %s\n", filename); 112 exit(1); 113 } 114 if (rc > 0) { 115 pos += (size_t)rc; 116 if (pos > size) { 117 size = pos + BLOCKSIZE; 118 result = realloc(result, size + 1); 119 } 120 } 121 } while(rc > 0); 122 123 close(f); 124 if (length != NULL) 125 *length = pos; 126 result[pos] = 0; 127 return result; 128 } 129 130 static int load_json(const char *filename); 131 static int process(const char *content, size_t length); 132 static void close_json(void); 133 134 int main(int ac, char **av) 135 { 136 char *t; 137 const char *f; 138 char *prog = *av; 139 int s; 140 size_t length; 141 142 (void)ac; /* unused */ 143 flags = Mustach_With_AllExtensions; 144 output = stdout; 145 146 for( ++av ; av[0] && av[0][0] == '-' && av[0][1] != 0 ; av++) { 147 if (!strcmp(*av, "-h") || !strcmp(*av, "--help")) 148 help(prog); 149 if (!strcmp(*av, "-s") || !strcmp(*av, "--strict")) 150 flags |= Mustach_With_ErrorUndefined; 151 } 152 if (*av) { 153 f = (av[0][0] == '-' && !av[0][1]) ? "/dev/stdin" : av[0]; 154 s = load_json(f); 155 if (s < 0) { 156 fprintf(stderr, "Can't load json file %s\n", av[0]); 157 if(errmsg) 158 fprintf(stderr, " reason: %s\n", errmsg); 159 exit(1); 160 } 161 while(*++av) { 162 t = readfile(*av, &length); 163 s = process(t, length); 164 free(t); 165 if (s != MUSTACH_OK) { 166 s = -s; 167 if (s < 1 || s >= (int)(sizeof errors / sizeof * errors)) 168 s = 0; 169 fprintf(stderr, "Template error %s (file %s)\n", errors[s], *av); 170 } 171 } 172 close_json(); 173 } 174 return 0; 175 } 176 177 #define MUSTACH_TOOL_JSON_C 1 178 #define MUSTACH_TOOL_JANSSON 2 179 #define MUSTACH_TOOL_CJSON 3 180 181 #if TOOL == MUSTACH_TOOL_JSON_C 182 183 #include "mustach-json-c.h" 184 185 static struct json_object *o; 186 static int load_json(const char *filename) 187 { 188 o = json_object_from_file(filename); 189 #if JSON_C_VERSION_NUM >= 0x000D00 190 errmsg = json_util_get_last_err(); 191 if (errmsg != NULL) 192 return -1; 193 #endif 194 if (o == NULL) { 195 errmsg = "null json"; 196 return -1; 197 } 198 return 0; 199 } 200 static int process(const char *content, size_t length) 201 { 202 return mustach_json_c_file(content, length, o, flags, output); 203 } 204 static void close_json() 205 { 206 json_object_put(o); 207 } 208 209 #elif TOOL == MUSTACH_TOOL_JANSSON 210 211 #include "mustach-jansson.h" 212 213 static json_t *o; 214 static json_error_t e; 215 static int load_json(const char *filename) 216 { 217 o = json_load_file(filename, JSON_DECODE_ANY, &e); 218 if (o == NULL) { 219 errmsg = e.text; 220 return -1; 221 } 222 return 0; 223 } 224 static int process(const char *content, size_t length) 225 { 226 return mustach_jansson_file(content, length, o, flags, output); 227 } 228 static void close_json() 229 { 230 json_decref(o); 231 } 232 233 #elif TOOL == MUSTACH_TOOL_CJSON 234 235 #include "mustach-cjson.h" 236 237 static cJSON *o; 238 static int load_json(const char *filename) 239 { 240 char *t; 241 size_t length; 242 243 t = readfile(filename, &length); 244 o = t ? cJSON_ParseWithLength(t, length) : NULL; 245 free(t); 246 return -!o; 247 } 248 static int process(const char *content, size_t length) 249 { 250 return mustach_cJSON_file(content, length, o, flags, output); 251 } 252 static void close_json() 253 { 254 cJSON_Delete(o); 255 } 256 257 #else 258 #error "no defined json library" 259 #endif