Coverage Report

Created: 2022-03-14 07:00

/src/jsonnet/core/libjsonnet.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
Copyright 2015 Google Inc. All rights reserved.
3
4
Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7
8
    http://www.apache.org/licenses/LICENSE-2.0
9
10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16
17
#include <cerrno>
18
#include <cstdlib>
19
#include <cstring>
20
21
#include <exception>
22
#include <fstream>
23
#include <iostream>
24
#include <sstream>
25
#include <string>
26
27
extern "C" {
28
#include "libjsonnet.h"
29
#include "libjsonnet_fmt.h"
30
}
31
32
#include "desugarer.h"
33
#include "formatter.h"
34
#include "json.h"
35
#include "parser.h"
36
#include "static_analysis.h"
37
#include "vm.h"
38
39
static void memory_panic(void)
40
0
{
41
0
    fputs("FATAL ERROR: a memory allocation error occurred.\n", stderr);
42
0
    abort();
43
0
}
44
45
static char *from_string(JsonnetVm *vm, const std::string &v)
46
431
{
47
431
    char *r = jsonnet_realloc(vm, nullptr, v.length() + 1);
48
431
    std::strcpy(r, v.c_str());
49
431
    return r;
50
431
}
51
52
static char *default_import_callback(void *ctx, const char *dir, const char *file,
53
                                     char **found_here_cptr, int *success);
54
55
const char *jsonnet_json_extract_string(JsonnetVm *vm, const struct JsonnetJsonValue *v)
56
0
{
57
0
    (void)vm;
58
0
    if (v->kind != JsonnetJsonValue::STRING)
59
0
        return nullptr;
60
0
    return v->string.c_str();
61
0
}
62
63
int jsonnet_json_extract_number(struct JsonnetVm *vm, const struct JsonnetJsonValue *v, double *out)
64
0
{
65
0
    (void)vm;
66
0
    if (v->kind != JsonnetJsonValue::NUMBER)
67
0
        return 0;
68
0
    *out = v->number;
69
0
    return 1;
70
0
}
71
72
int jsonnet_json_extract_bool(struct JsonnetVm *vm, const struct JsonnetJsonValue *v)
73
0
{
74
0
    (void)vm;
75
0
    if (v->kind != JsonnetJsonValue::BOOL)
76
0
        return 2;
77
0
    return v->number != 0;
78
0
}
79
80
int jsonnet_json_extract_null(struct JsonnetVm *vm, const struct JsonnetJsonValue *v)
81
0
{
82
0
    (void)vm;
83
0
    return v->kind == JsonnetJsonValue::NULL_KIND;
84
0
}
85
86
JsonnetJsonValue *jsonnet_json_make_string(JsonnetVm *vm, const char *v)
87
0
{
88
0
    (void)vm;
89
0
    JsonnetJsonValue *r = new JsonnetJsonValue();
90
0
    r->kind = JsonnetJsonValue::STRING;
91
0
    r->string = v;
92
0
    return r;
93
0
}
94
95
JsonnetJsonValue *jsonnet_json_make_number(struct JsonnetVm *vm, double v)
96
0
{
97
0
    (void)vm;
98
0
    JsonnetJsonValue *r = new JsonnetJsonValue();
99
0
    r->kind = JsonnetJsonValue::NUMBER;
100
0
    r->number = v;
101
0
    return r;
102
0
}
103
104
JsonnetJsonValue *jsonnet_json_make_bool(struct JsonnetVm *vm, int v)
105
0
{
106
0
    (void)vm;
107
0
    JsonnetJsonValue *r = new JsonnetJsonValue();
108
0
    r->kind = JsonnetJsonValue::BOOL;
109
0
    r->number = v != 0;
110
0
    return r;
111
0
}
112
113
JsonnetJsonValue *jsonnet_json_make_null(struct JsonnetVm *vm)
114
0
{
115
0
    (void)vm;
116
0
    JsonnetJsonValue *r = new JsonnetJsonValue();
117
0
    r->kind = JsonnetJsonValue::NULL_KIND;
118
0
    return r;
119
0
}
120
121
JsonnetJsonValue *jsonnet_json_make_array(JsonnetVm *vm)
122
0
{
123
0
    (void)vm;
124
0
    JsonnetJsonValue *r = new JsonnetJsonValue();
125
0
    r->kind = JsonnetJsonValue::ARRAY;
126
0
    return r;
127
0
}
128
129
void jsonnet_json_array_append(JsonnetVm *vm, JsonnetJsonValue *arr, JsonnetJsonValue *v)
130
0
{
131
0
    (void)vm;
132
0
    assert(arr->kind == JsonnetJsonValue::ARRAY);
133
0
    arr->elements.emplace_back(v);
134
0
}
135
136
JsonnetJsonValue *jsonnet_json_make_object(JsonnetVm *vm)
137
0
{
138
0
    (void)vm;
139
0
    JsonnetJsonValue *r = new JsonnetJsonValue();
140
0
    r->kind = JsonnetJsonValue::OBJECT;
141
0
    return r;
142
0
}
143
144
void jsonnet_json_object_append(JsonnetVm *vm, JsonnetJsonValue *obj, const char *f,
145
                                JsonnetJsonValue *v)
146
0
{
147
0
    (void)vm;
148
0
    assert(obj->kind == JsonnetJsonValue::OBJECT);
149
0
    obj->fields[std::string(f)] = std::unique_ptr<JsonnetJsonValue>(v);
150
0
}
151
152
void jsonnet_json_destroy(JsonnetVm *vm, JsonnetJsonValue *v)
153
0
{
154
0
    (void)vm;
155
0
    delete v;
156
0
}
157
158
struct JsonnetVm {
159
    double gcGrowthTrigger;
160
    unsigned maxStack;
161
    unsigned gcMinObjects;
162
    unsigned maxTrace;
163
    std::map<std::string, VmExt> ext;
164
    std::map<std::string, VmExt> tla;
165
    JsonnetImportCallback *importCallback;
166
    VmNativeCallbackMap nativeCallbacks;
167
    void *importCallbackContext;
168
    bool stringOutput;
169
    std::vector<std::string> jpaths;
170
171
    FmtOpts fmtOpts;
172
    bool fmtDebugDesugaring;
173
174
    JsonnetVm(void)
175
        : gcGrowthTrigger(2.0),
176
          maxStack(500),
177
          gcMinObjects(1000),
178
          maxTrace(20),
179
          importCallback(default_import_callback),
180
          importCallbackContext(this),
181
          stringOutput(false),
182
          fmtDebugDesugaring(false)
183
431
    {
184
431
        jpaths.emplace_back("/usr/share/jsonnet-" + std::string(jsonnet_version()) + "/");
185
431
        jpaths.emplace_back("/usr/local/share/jsonnet-" + std::string(jsonnet_version()) + "/");
186
431
    }
187
};
188
189
enum ImportStatus { IMPORT_STATUS_OK, IMPORT_STATUS_FILE_NOT_FOUND, IMPORT_STATUS_IO_ERROR };
190
191
static enum ImportStatus try_path(const std::string &dir, const std::string &rel,
192
                                  std::string &content, std::string &found_here,
193
                                  std::string &err_msg)
194
0
{
195
0
    std::string abs_path;
196
0
    if (rel.length() == 0) {
197
0
        err_msg = "the empty string is not a valid filename";
198
0
        return IMPORT_STATUS_IO_ERROR;
199
0
    }
200
    // It is possible that rel is actually absolute.
201
0
    if (rel[0] == '/') {
202
0
        abs_path = rel;
203
0
    } else {
204
0
        abs_path = dir + rel;
205
0
    }
206
207
0
    if (abs_path[abs_path.length() - 1] == '/') {
208
0
        err_msg = "attempted to import a directory";
209
0
        return IMPORT_STATUS_IO_ERROR;
210
0
    }
211
212
0
    std::ifstream f;
213
0
    f.open(abs_path.c_str());
214
0
    if (!f.good())
215
0
        return IMPORT_STATUS_FILE_NOT_FOUND;
216
0
    try {
217
0
        content.assign(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>());
218
0
    } catch (const std::ios_base::failure &io_err) {
219
0
        err_msg = io_err.what();
220
0
        return IMPORT_STATUS_IO_ERROR;
221
0
    }
222
0
    if (!f.good()) {
223
0
        err_msg = strerror(errno);
224
0
        return IMPORT_STATUS_IO_ERROR;
225
0
    }
226
227
0
    found_here = abs_path;
228
229
0
    return IMPORT_STATUS_OK;
230
0
}
231
232
static char *default_import_callback(void *ctx, const char *dir, const char *file,
233
                                     char **found_here_cptr, int *success)
234
0
{
235
0
    auto *vm = static_cast<JsonnetVm *>(ctx);
236
237
0
    std::string input, found_here, err_msg;
238
239
0
    ImportStatus status = try_path(dir, file, input, found_here, err_msg);
240
241
0
    std::vector<std::string> jpaths(vm->jpaths);
242
243
    // If not found, try library search path.
244
0
    while (status == IMPORT_STATUS_FILE_NOT_FOUND) {
245
0
        if (jpaths.size() == 0) {
246
0
            *success = 0;
247
0
            const char *err = "no match locally or in the Jsonnet library paths.";
248
0
            char *r = jsonnet_realloc(vm, nullptr, std::strlen(err) + 1);
249
0
            std::strcpy(r, err);
250
0
            return r;
251
0
        }
252
0
        status = try_path(jpaths.back(), file, input, found_here, err_msg);
253
0
        jpaths.pop_back();
254
0
    }
255
256
0
    if (status == IMPORT_STATUS_IO_ERROR) {
257
0
        *success = 0;
258
0
        return from_string(vm, err_msg);
259
0
    } else {
260
0
        assert(status == IMPORT_STATUS_OK);
261
0
        *success = 1;
262
0
        *found_here_cptr = from_string(vm, found_here);
263
0
        return from_string(vm, input);
264
0
    }
265
0
}
266
267
1.29k
#define TRY try {
268
#define CATCH(func)                                                                           \
269
1.29k
    }                                                                                         \
270
1.29k
    catch (const std::bad_alloc &)                                                            \
271
1.29k
    {                                                                                         \
272
0
        memory_panic();                                                                       \
273
0
    }                                                                                         \
274
1.29k
    catch (const std::exception &e)                                                           \
275
1.29k
    {                                                                                         \
276
0
        std::cerr << "Something went wrong during " func ", please report this: " << e.what() \
277
0
                  << std::endl;                                                               \
278
0
        abort();                                                                              \
279
0
    }
280
281
const char *jsonnet_version(void)
282
862
{
283
862
    return LIB_JSONNET_VERSION;
284
862
}
285
286
JsonnetVm *jsonnet_make(void)
287
431
{
288
431
    TRY
289
431
        return new JsonnetVm();
290
431
    CATCH("jsonnet_make")
291
0
    return nullptr;
292
431
}
293
294
void jsonnet_destroy(JsonnetVm *vm)
295
431
{
296
431
    TRY
297
431
        delete vm;
298
431
    CATCH("jsonnet_destroy")
299
431
}
300
301
void jsonnet_max_stack(JsonnetVm *vm, unsigned v)
302
0
{
303
0
    vm->maxStack = v;
304
0
}
305
306
void jsonnet_gc_min_objects(JsonnetVm *vm, unsigned v)
307
0
{
308
0
    vm->gcMinObjects = v;
309
0
}
310
311
void jsonnet_gc_growth_trigger(JsonnetVm *vm, double v)
312
0
{
313
0
    vm->gcGrowthTrigger = v;
314
0
}
315
316
void jsonnet_string_output(struct JsonnetVm *vm, int v)
317
0
{
318
0
    vm->stringOutput = bool(v);
319
0
}
320
321
void jsonnet_import_callback(struct JsonnetVm *vm, JsonnetImportCallback *cb, void *ctx)
322
431
{
323
431
    vm->importCallback = cb;
324
431
    vm->importCallbackContext = ctx;
325
431
}
326
327
void jsonnet_native_callback(struct JsonnetVm *vm, const char *name, JsonnetNativeCallback *cb,
328
                             void *ctx, const char *const *params)
329
0
{
330
0
    std::vector<std::string> params2;
331
0
    for (; *params != nullptr; params++)
332
0
        params2.push_back(*params);
333
0
    vm->nativeCallbacks[name] = VmNativeCallback{cb, ctx, params2};
334
0
}
335
336
void jsonnet_ext_var(JsonnetVm *vm, const char *key, const char *val)
337
0
{
338
0
    vm->ext[key] = VmExt(val, false);
339
0
}
340
341
void jsonnet_ext_code(JsonnetVm *vm, const char *key, const char *val)
342
0
{
343
0
    vm->ext[key] = VmExt(val, true);
344
0
}
345
346
void jsonnet_tla_var(JsonnetVm *vm, const char *key, const char *val)
347
0
{
348
0
    vm->tla[key] = VmExt(val, false);
349
0
}
350
351
void jsonnet_tla_code(JsonnetVm *vm, const char *key, const char *val)
352
0
{
353
0
    vm->tla[key] = VmExt(val, true);
354
0
}
355
356
void jsonnet_fmt_debug_desugaring(JsonnetVm *vm, int v)
357
0
{
358
0
    vm->fmtDebugDesugaring = v;
359
0
}
360
361
void jsonnet_fmt_indent(JsonnetVm *vm, int v)
362
0
{
363
0
    vm->fmtOpts.indent = v;
364
0
}
365
366
void jsonnet_fmt_max_blank_lines(JsonnetVm *vm, int v)
367
0
{
368
0
    vm->fmtOpts.maxBlankLines = v;
369
0
}
370
371
void jsonnet_fmt_string(JsonnetVm *vm, int v)
372
0
{
373
0
    if (v != 'd' && v != 's' && v != 'l')
374
0
        v = 'l';
375
0
    vm->fmtOpts.stringStyle = v;
376
0
}
377
378
void jsonnet_fmt_comment(JsonnetVm *vm, int v)
379
0
{
380
0
    if (v != 'h' && v != 's' && v != 'l')
381
0
        v = 'l';
382
0
    vm->fmtOpts.commentStyle = v;
383
0
}
384
385
void jsonnet_fmt_pad_arrays(JsonnetVm *vm, int v)
386
0
{
387
0
    vm->fmtOpts.padArrays = v;
388
0
}
389
390
void jsonnet_fmt_pad_objects(JsonnetVm *vm, int v)
391
0
{
392
0
    vm->fmtOpts.padObjects = v;
393
0
}
394
395
void jsonnet_fmt_pretty_field_names(JsonnetVm *vm, int v)
396
0
{
397
0
    vm->fmtOpts.prettyFieldNames = v;
398
0
}
399
400
void jsonnet_fmt_sort_imports(JsonnetVm *vm, int v)
401
0
{
402
0
    vm->fmtOpts.sortImports = v;
403
0
}
404
405
void jsonnet_max_trace(JsonnetVm *vm, unsigned v)
406
0
{
407
0
    vm->maxTrace = v;
408
0
}
409
410
void jsonnet_jpath_add(JsonnetVm *vm, const char *path_)
411
0
{
412
0
    if (std::strlen(path_) == 0)
413
0
        return;
414
0
    std::string path = path_;
415
0
    if (path[path.length() - 1] != '/')
416
0
        path += '/';
417
0
    vm->jpaths.emplace_back(path);
418
0
}
419
420
static char *jsonnet_fmt_snippet_aux(JsonnetVm *vm, const char *filename, const char *snippet,
421
                                     int *error)
422
0
{
423
0
    try {
424
0
        Allocator alloc;
425
0
        std::string json_str;
426
0
        AST *expr;
427
0
        std::map<std::string, std::string> files;
428
0
        Tokens tokens = jsonnet_lex(filename, snippet);
429
430
0
        expr = jsonnet_parse(&alloc, tokens);
431
0
        Fodder final_fodder = tokens.front().fodder;
432
433
0
        if (vm->fmtDebugDesugaring)
434
0
            jsonnet_desugar(&alloc, expr, &vm->tla);
435
436
0
        json_str = jsonnet_fmt(expr, final_fodder, vm->fmtOpts);
437
438
0
        *error = false;
439
0
        return from_string(vm, json_str);
440
441
0
    } catch (StaticError &e) {
442
0
        std::stringstream ss;
443
0
        ss << "STATIC ERROR: " << e << std::endl;
444
0
        *error = true;
445
0
        return from_string(vm, ss.str());
446
0
    }
447
0
}
448
449
char *jsonnet_fmt_file(JsonnetVm *vm, const char *filename, int *error)
450
0
{
451
0
    TRY
452
0
        std::ifstream f;
453
0
        f.open(filename);
454
0
        if (!f.good()) {
455
0
            std::stringstream ss;
456
0
            ss << "Opening input file: " << filename << ": " << strerror(errno);
457
0
            *error = true;
458
0
            return from_string(vm, ss.str());
459
0
        }
460
0
        std::string input;
461
0
        input.assign(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>());
462
463
0
        return jsonnet_fmt_snippet_aux(vm, filename, input.c_str(), error);
464
0
    CATCH("jsonnet_fmt_file")
465
0
    return nullptr;  // Never happens.
466
0
}
467
468
char *jsonnet_fmt_snippet(JsonnetVm *vm, const char *filename, const char *snippet, int *error)
469
0
{
470
0
    TRY
471
0
        return jsonnet_fmt_snippet_aux(vm, filename, snippet, error);
472
0
    CATCH("jsonnet_fmt_snippet")
473
0
    return nullptr;  // Never happens.
474
0
}
475
476
namespace {
477
enum EvalKind { REGULAR, MULTI, STREAM };
478
}  // namespace
479
480
static char *jsonnet_evaluate_snippet_aux(JsonnetVm *vm, const char *filename, const char *snippet,
481
                                          int *error, EvalKind kind)
482
431
{
483
431
    try {
484
431
        Allocator alloc;
485
431
        AST *expr;
486
431
        Tokens tokens = jsonnet_lex(filename, snippet);
487
488
431
        expr = jsonnet_parse(&alloc, tokens);
489
490
431
        jsonnet_desugar(&alloc, expr, &vm->tla);
491
492
431
        unsigned max_stack = vm->maxStack;
493
494
        // For the stdlib desugaring.
495
431
        max_stack++;
496
497
        // For the TLA desugaring.
498
431
        max_stack++;
499
500
431
        jsonnet_static_analysis(expr);
501
431
        switch (kind) {
502
212
            case REGULAR: {
503
212
                std::string json_str = jsonnet_vm_execute(&alloc,
504
212
                                                          expr,
505
212
                                                          vm->ext,
506
212
                                                          max_stack,
507
212
                                                          vm->gcMinObjects,
508
212
                                                          vm->gcGrowthTrigger,
509
212
                                                          vm->nativeCallbacks,
510
212
                                                          vm->importCallback,
511
212
                                                          vm->importCallbackContext,
512
212
                                                          vm->stringOutput);
513
212
                json_str += "\n";
514
212
                *error = false;
515
212
                return from_string(vm, json_str);
516
0
            } break;
517
518
0
            case MULTI: {
519
0
                std::map<std::string, std::string> files =
520
0
                    jsonnet_vm_execute_multi(&alloc,
521
0
                                             expr,
522
0
                                             vm->ext,
523
0
                                             max_stack,
524
0
                                             vm->gcMinObjects,
525
0
                                             vm->gcGrowthTrigger,
526
0
                                             vm->nativeCallbacks,
527
0
                                             vm->importCallback,
528
0
                                             vm->importCallbackContext,
529
0
                                             vm->stringOutput);
530
0
                size_t sz = 1;  // final sentinel
531
0
                for (const auto &pair : files) {
532
0
                    sz += pair.first.length() + 1;   // include sentinel
533
0
                    sz += pair.second.length() + 2;  // Add a '\n' as well as sentinel
534
0
                }
535
0
                char *buf = (char *)::malloc(sz);
536
0
                if (buf == nullptr)
537
0
                    memory_panic();
538
0
                std::ptrdiff_t i = 0;
539
0
                for (const auto &pair : files) {
540
0
                    memcpy(&buf[i], pair.first.c_str(), pair.first.length() + 1);
541
0
                    i += pair.first.length() + 1;
542
0
                    memcpy(&buf[i], pair.second.c_str(), pair.second.length());
543
0
                    i += pair.second.length();
544
0
                    buf[i] = '\n';
545
0
                    i++;
546
0
                    buf[i] = '\0';
547
0
                    i++;
548
0
                }
549
0
                buf[i] = '\0';  // final sentinel
550
0
                *error = false;
551
0
                return buf;
552
0
            } break;
553
554
0
            case STREAM: {
555
0
                std::vector<std::string> documents =
556
0
                    jsonnet_vm_execute_stream(&alloc,
557
0
                                              expr,
558
0
                                              vm->ext,
559
0
                                              max_stack,
560
0
                                              vm->gcMinObjects,
561
0
                                              vm->gcGrowthTrigger,
562
0
                                              vm->nativeCallbacks,
563
0
                                              vm->importCallback,
564
0
                                              vm->importCallbackContext,
565
0
                                              vm->stringOutput);
566
0
                size_t sz = 1;  // final sentinel
567
0
                for (const auto &doc : documents) {
568
0
                    sz += doc.length() + 2;  // Add a '\n' as well as sentinel
569
0
                }
570
0
                char *buf = (char *)::malloc(sz);
571
0
                if (buf == nullptr)
572
0
                    memory_panic();
573
0
                std::ptrdiff_t i = 0;
574
0
                for (const auto &doc : documents) {
575
0
                    memcpy(&buf[i], doc.c_str(), doc.length());
576
0
                    i += doc.length();
577
0
                    buf[i] = '\n';
578
0
                    i++;
579
0
                    buf[i] = '\0';
580
0
                    i++;
581
0
                }
582
0
                buf[i] = '\0';  // final sentinel
583
0
                *error = false;
584
0
                return buf;
585
0
            } break;
586
587
0
            default:
588
0
                fputs("INTERNAL ERROR: bad value of 'kind', probably memory corruption.\n", stderr);
589
0
                abort();
590
431
        }
591
592
431
    } catch (StaticError &e) {
593
219
        std::stringstream ss;
594
219
        ss << "STATIC ERROR: " << e << std::endl;
595
219
        *error = true;
596
219
        return from_string(vm, ss.str());
597
598
219
    } catch (RuntimeError &e) {
599
80
        std::stringstream ss;
600
80
        ss << "RUNTIME ERROR: " << e.msg << std::endl;
601
80
        const long max_above = vm->maxTrace / 2;
602
80
        const long max_below = vm->maxTrace - max_above;
603
80
        const long sz = e.stackTrace.size();
604
3.34k
        for (long i = 0; i < sz; ++i) {
605
3.26k
            const auto &f = e.stackTrace[i];
606
3.26k
            if (vm->maxTrace > 0 && i >= max_above && i < sz - max_below) {
607
2.88k
                if (i == max_above)
608
9
                    ss << "\t..." << std::endl;
609
2.88k
            } else {
610
374
                ss << "\t" << f.location << "\t" << f.name << std::endl;
611
374
            }
612
3.26k
        }
613
80
        *error = true;
614
80
        return from_string(vm, ss.str());
615
80
    }
616
617
0
    return nullptr;  // Quiet, compiler.
618
431
}
619
620
static char *jsonnet_evaluate_file_aux(JsonnetVm *vm, const char *filename, int *error,
621
                                       EvalKind kind)
622
0
{
623
0
    std::ifstream f;
624
0
    f.open(filename);
625
0
    if (!f.good()) {
626
0
        std::stringstream ss;
627
0
        ss << "Opening input file: " << filename << ": " << strerror(errno);
628
0
        *error = true;
629
0
        return from_string(vm, ss.str());
630
0
    }
631
0
    std::string input;
632
0
    input.assign(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>());
633
634
0
    return jsonnet_evaluate_snippet_aux(vm, filename, input.c_str(), error, kind);
635
0
}
636
637
char *jsonnet_evaluate_file(JsonnetVm *vm, const char *filename, int *error)
638
0
{
639
0
    TRY
640
0
        return jsonnet_evaluate_file_aux(vm, filename, error, REGULAR);
641
0
    CATCH("jsonnet_evaluate_file")
642
0
    return nullptr;  // Never happens.
643
0
}
644
645
char *jsonnet_evaluate_file_multi(JsonnetVm *vm, const char *filename, int *error)
646
0
{
647
0
    TRY
648
0
        return jsonnet_evaluate_file_aux(vm, filename, error, MULTI);
649
0
    CATCH("jsonnet_evaluate_file_multi")
650
0
    return nullptr;  // Never happens.
651
0
}
652
653
char *jsonnet_evaluate_file_stream(JsonnetVm *vm, const char *filename, int *error)
654
0
{
655
0
    TRY
656
0
        return jsonnet_evaluate_file_aux(vm, filename, error, STREAM);
657
0
    CATCH("jsonnet_evaluate_file_stream")
658
0
    return nullptr;  // Never happens.
659
0
}
660
661
char *jsonnet_evaluate_snippet(JsonnetVm *vm, const char *filename, const char *snippet, int *error)
662
431
{
663
431
    TRY
664
431
        return jsonnet_evaluate_snippet_aux(vm, filename, snippet, error, REGULAR);
665
431
    CATCH("jsonnet_evaluate_snippet")
666
0
    return nullptr;  // Never happens.
667
431
}
668
669
char *jsonnet_evaluate_snippet_multi(JsonnetVm *vm, const char *filename, const char *snippet,
670
                                     int *error)
671
0
{
672
0
    TRY
673
0
        return jsonnet_evaluate_snippet_aux(vm, filename, snippet, error, MULTI);
674
0
    CATCH("jsonnet_evaluate_snippet_multi")
675
0
    return nullptr;  // Never happens.
676
0
}
677
678
char *jsonnet_evaluate_snippet_stream(JsonnetVm *vm, const char *filename, const char *snippet,
679
                                      int *error)
680
0
{
681
0
    TRY
682
0
        return jsonnet_evaluate_snippet_aux(vm, filename, snippet, error, STREAM);
683
0
    CATCH("jsonnet_evaluate_snippet_stream")
684
0
    return nullptr;  // Never happens.
685
0
}
686
687
char *jsonnet_realloc(JsonnetVm *vm, char *str, size_t sz)
688
882
{
689
882
    (void)vm;
690
882
    if (str == nullptr) {
691
451
        if (sz == 0)
692
0
            return nullptr;
693
451
        auto *r = static_cast<char *>(::malloc(sz));
694
451
        if (r == nullptr)
695
0
            memory_panic();
696
451
        return r;
697
451
    } else {
698
431
        if (sz == 0) {
699
431
            ::free(str);
700
431
            return nullptr;
701
431
        } else {
702
0
            auto *r = static_cast<char *>(::realloc(str, sz));
703
0
            if (r == nullptr)
704
0
                memory_panic();
705
0
            return r;
706
0
        }
707
431
    }
708
882
}