Coverage Report

Created: 2023-06-07 06:17

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