oj 1.2.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of oj might be problematic. Click here for more details.
- data/README.md +3 -3
- data/ext/oj/dump.c +79 -87
- data/ext/oj/extconf.rb +32 -2
- data/ext/oj/fast.c +26 -37
- data/ext/oj/load.c +83 -79
- data/ext/oj/oj.c +120 -117
- data/ext/oj/oj.h +28 -39
- data/lib/oj/version.rb +1 -1
- data/test/tests.rb +119 -15
- metadata +3 -2
data/ext/oj/oj.c
CHANGED
@@ -43,13 +43,13 @@
|
|
43
43
|
#define SMALL_JSON 65536
|
44
44
|
|
45
45
|
typedef struct _YesNoOpt {
|
46
|
-
VALUE
|
47
|
-
char
|
46
|
+
VALUE sym;
|
47
|
+
char *attr;
|
48
48
|
} *YesNoOpt;
|
49
49
|
|
50
50
|
void Init_oj();
|
51
51
|
|
52
|
-
VALUE
|
52
|
+
VALUE Oj = Qnil;
|
53
53
|
|
54
54
|
ID oj_as_json_id;
|
55
55
|
ID oj_fileno_id;
|
@@ -63,6 +63,7 @@ ID oj_to_sym_id;
|
|
63
63
|
ID oj_write_id;
|
64
64
|
ID oj_tv_nsec_id;
|
65
65
|
ID oj_tv_sec_id;
|
66
|
+
ID oj_tv_usec_id;
|
66
67
|
|
67
68
|
VALUE oj_bag_class;
|
68
69
|
VALUE oj_date_class;
|
@@ -93,10 +94,10 @@ static VALUE symbolize_names_sym;
|
|
93
94
|
static VALUE mimic = Qnil;
|
94
95
|
static VALUE keep = Qnil;
|
95
96
|
|
96
|
-
Cache
|
97
|
-
Cache
|
97
|
+
Cache oj_class_cache = 0;
|
98
|
+
Cache oj_attr_cache = 0;
|
98
99
|
|
99
|
-
#
|
100
|
+
#if HAS_ENCODING_SUPPORT
|
100
101
|
rb_encoding *oj_utf8_encoding = 0;
|
101
102
|
#endif
|
102
103
|
|
@@ -124,7 +125,7 @@ static VALUE define_mimic_json(VALUE self);
|
|
124
125
|
*/
|
125
126
|
static VALUE
|
126
127
|
get_def_opts(VALUE self) {
|
127
|
-
VALUE
|
128
|
+
VALUE opts = rb_hash_new();
|
128
129
|
|
129
130
|
rb_hash_aset(opts, indent_sym, INT2FIX(oj_default_options.indent));
|
130
131
|
rb_hash_aset(opts, circular_sym, (Yes == oj_default_options.circular) ? Qtrue : ((No == oj_default_options.circular) ? Qfalse : Qnil));
|
@@ -136,7 +137,7 @@ get_def_opts(VALUE self) {
|
|
136
137
|
case CompatMode: rb_hash_aset(opts, mode_sym, compat_sym); break;
|
137
138
|
case NullMode: rb_hash_aset(opts, mode_sym, null_sym); break;
|
138
139
|
case ObjectMode:
|
139
|
-
default:
|
140
|
+
default: rb_hash_aset(opts, mode_sym, object_sym); break;
|
140
141
|
}
|
141
142
|
return opts;
|
142
143
|
}
|
@@ -151,53 +152,53 @@ get_def_opts(VALUE self) {
|
|
151
152
|
* @param [true|false|nil] :symbol_keys convert hash keys to symbols
|
152
153
|
* @param [true|false|nil] :ascii_only encode all high-bit characters as escaped sequences if true
|
153
154
|
* @param [:object|:strict|:compat|:null] load and dump mode to use for JSON
|
154
|
-
*
|
155
|
-
*
|
156
|
-
*
|
157
|
-
*
|
158
|
-
*
|
159
|
-
*
|
160
|
-
*
|
155
|
+
* :strict raises an exception when a non-supported Object is
|
156
|
+
* encountered. :compat attempts to extract variable values from an
|
157
|
+
* Object using to_json() or to_hash() then it walks the Object's
|
158
|
+
* variables if neither is found. The :object mode ignores to_hash()
|
159
|
+
* and to_json() methods and encodes variables using code internal to
|
160
|
+
* the Oj gem. The :null mode ignores non-supported Objects and
|
161
|
+
* replaces them with a null. @return [nil]
|
161
162
|
*/
|
162
163
|
static VALUE
|
163
164
|
set_def_opts(VALUE self, VALUE opts) {
|
164
|
-
struct _YesNoOpt
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
165
|
+
struct _YesNoOpt ynos[] = {
|
166
|
+
{ circular_sym, &oj_default_options.circular },
|
167
|
+
{ auto_define_sym, &oj_default_options.auto_define },
|
168
|
+
{ symbol_keys_sym, &oj_default_options.sym_key },
|
169
|
+
{ ascii_only_sym, &oj_default_options.ascii_only },
|
170
|
+
{ Qnil, 0 }
|
170
171
|
};
|
171
|
-
YesNoOpt
|
172
|
-
VALUE
|
172
|
+
YesNoOpt o;
|
173
|
+
VALUE v;
|
173
174
|
|
174
175
|
Check_Type(opts, T_HASH);
|
175
176
|
v = rb_hash_aref(opts, indent_sym);
|
176
177
|
if (Qnil != v) {
|
177
|
-
|
178
|
-
|
178
|
+
Check_Type(v, T_FIXNUM);
|
179
|
+
oj_default_options.indent = FIX2INT(v);
|
179
180
|
}
|
180
181
|
|
181
182
|
v = rb_hash_lookup(opts, mode_sym);
|
182
183
|
if (Qnil == v) {
|
183
184
|
// ignore
|
184
185
|
} else if (object_sym == v) {
|
185
|
-
|
186
|
+
oj_default_options.mode = ObjectMode;
|
186
187
|
} else if (strict_sym == v) {
|
187
|
-
|
188
|
+
oj_default_options.mode = StrictMode;
|
188
189
|
} else if (compat_sym == v) {
|
189
|
-
|
190
|
+
oj_default_options.mode = CompatMode;
|
190
191
|
} else if (null_sym == v) {
|
191
|
-
|
192
|
+
oj_default_options.mode = NullMode;
|
192
193
|
} else {
|
193
|
-
|
194
|
+
rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, or :null.\n");
|
194
195
|
}
|
195
196
|
|
196
197
|
for (o = ynos; 0 != o->attr; o++) {
|
197
198
|
if (Qtrue != rb_funcall(opts, rb_intern("has_key?"), 1, o->sym)) {
|
198
199
|
continue;
|
199
200
|
}
|
200
|
-
|
201
|
+
if (Qnil != (v = rb_hash_lookup(opts, o->sym))) {
|
201
202
|
if (Qtrue == v) {
|
202
203
|
*o->attr = Yes;
|
203
204
|
} else if (Qfalse == v) {
|
@@ -212,54 +213,54 @@ set_def_opts(VALUE self, VALUE opts) {
|
|
212
213
|
|
213
214
|
static void
|
214
215
|
parse_options(VALUE ropts, Options copts) {
|
215
|
-
struct _YesNoOpt
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
216
|
+
struct _YesNoOpt ynos[] = {
|
217
|
+
{ circular_sym, &copts->circular },
|
218
|
+
{ auto_define_sym, &copts->auto_define },
|
219
|
+
{ symbol_keys_sym, &copts->sym_key },
|
220
|
+
{ ascii_only_sym, &copts->ascii_only },
|
221
|
+
{ Qnil, 0 }
|
221
222
|
};
|
222
|
-
YesNoOpt
|
223
|
+
YesNoOpt o;
|
223
224
|
|
224
225
|
if (rb_cHash == rb_obj_class(ropts)) {
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
226
|
+
VALUE v;
|
227
|
+
|
228
|
+
if (Qnil != (v = rb_hash_lookup(ropts, indent_sym))) {
|
229
|
+
if (rb_cFixnum != rb_obj_class(v)) {
|
230
|
+
rb_raise(rb_eArgError, ":indent must be a Fixnum.\n");
|
231
|
+
}
|
232
|
+
copts->indent = NUM2INT(v);
|
233
|
+
}
|
234
|
+
if (Qnil != (v = rb_hash_lookup(ropts, mode_sym))) {
|
235
|
+
if (object_sym == v) {
|
236
|
+
copts->mode = ObjectMode;
|
237
|
+
} else if (strict_sym == v) {
|
238
|
+
copts->mode = StrictMode;
|
239
|
+
} else if (compat_sym == v) {
|
240
|
+
copts->mode = CompatMode;
|
241
|
+
} else if (null_sym == v) {
|
242
|
+
copts->mode = NullMode;
|
243
|
+
} else {
|
244
|
+
rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, or :null.\n");
|
245
|
+
}
|
246
|
+
}
|
247
|
+
for (o = ynos; 0 != o->attr; o++) {
|
248
|
+
if (Qnil != (v = rb_hash_lookup(ropts, o->sym))) {
|
249
|
+
if (Qtrue == v) {
|
250
|
+
*o->attr = Yes;
|
251
|
+
} else if (Qfalse == v) {
|
252
|
+
*o->attr = No;
|
253
|
+
} else {
|
254
|
+
rb_raise(rb_eArgError, "%s must be true or false.\n", rb_id2name(SYM2ID(o->sym)));
|
255
|
+
}
|
256
|
+
}
|
257
|
+
}
|
257
258
|
}
|
258
259
|
}
|
259
260
|
|
260
261
|
static VALUE
|
261
262
|
load_with_opts(VALUE input, Options copts) {
|
262
|
-
char
|
263
|
+
char *json;
|
263
264
|
size_t len;
|
264
265
|
VALUE obj;
|
265
266
|
|
@@ -343,17 +344,17 @@ load(int argc, VALUE *argv, VALUE self) {
|
|
343
344
|
|
344
345
|
static VALUE
|
345
346
|
load_file(int argc, VALUE *argv, VALUE self) {
|
346
|
-
char
|
347
|
-
char
|
348
|
-
FILE
|
349
|
-
unsigned long
|
347
|
+
char *path;
|
348
|
+
char *json;
|
349
|
+
FILE *f;
|
350
|
+
unsigned long len;
|
350
351
|
VALUE obj;
|
351
352
|
struct _Options options = oj_default_options;
|
352
353
|
|
353
354
|
Check_Type(*argv, T_STRING);
|
354
355
|
path = StringValuePtr(*argv);
|
355
356
|
if (0 == (f = fopen(path, "r"))) {
|
356
|
-
|
357
|
+
rb_raise(rb_eIOError, "%s\n", strerror(errno));
|
357
358
|
}
|
358
359
|
fseek(f, 0, SEEK_END);
|
359
360
|
len = ftell(f);
|
@@ -364,8 +365,8 @@ load_file(int argc, VALUE *argv, VALUE self) {
|
|
364
365
|
}
|
365
366
|
fseek(f, 0, SEEK_SET);
|
366
367
|
if (len != fread(json, 1, len, f)) {
|
367
|
-
|
368
|
-
|
368
|
+
fclose(f);
|
369
|
+
rb_raise(rb_eLoadError, "Failed to read %ld bytes from %s.\n", len, path);
|
369
370
|
}
|
370
371
|
fclose(f);
|
371
372
|
json[len] = '\0';
|
@@ -387,18 +388,18 @@ load_file(int argc, VALUE *argv, VALUE self) {
|
|
387
388
|
*/
|
388
389
|
static VALUE
|
389
390
|
dump(int argc, VALUE *argv, VALUE self) {
|
390
|
-
char
|
391
|
-
struct _Options
|
392
|
-
VALUE
|
391
|
+
char *json;
|
392
|
+
struct _Options copts = oj_default_options;
|
393
|
+
VALUE rstr;
|
393
394
|
|
394
395
|
if (2 == argc) {
|
395
|
-
|
396
|
+
parse_options(argv[1], &copts);
|
396
397
|
}
|
397
398
|
if (0 == (json = oj_write_obj_to_str(*argv, &copts))) {
|
398
|
-
|
399
|
+
rb_raise(rb_eNoMemError, "Not enough memory.\n");
|
399
400
|
}
|
400
401
|
rstr = rb_str_new2(json);
|
401
|
-
#
|
402
|
+
#if HAS_ENCODING_SUPPORT
|
402
403
|
rb_enc_associate(rstr, oj_utf8_encoding);
|
403
404
|
#endif
|
404
405
|
xfree(json);
|
@@ -418,10 +419,10 @@ dump(int argc, VALUE *argv, VALUE self) {
|
|
418
419
|
*/
|
419
420
|
static VALUE
|
420
421
|
to_file(int argc, VALUE *argv, VALUE self) {
|
421
|
-
struct _Options
|
422
|
+
struct _Options copts = oj_default_options;
|
422
423
|
|
423
424
|
if (3 == argc) {
|
424
|
-
|
425
|
+
parse_options(argv[2], &copts);
|
425
426
|
}
|
426
427
|
Check_Type(*argv, T_STRING);
|
427
428
|
oj_write_obj_to_file(argv[1], StringValuePtr(*argv), &copts);
|
@@ -433,15 +434,15 @@ to_file(int argc, VALUE *argv, VALUE self) {
|
|
433
434
|
|
434
435
|
static VALUE
|
435
436
|
mimic_dump(int argc, VALUE *argv, VALUE self) {
|
436
|
-
char
|
437
|
-
struct _Options
|
438
|
-
VALUE
|
437
|
+
char *json;
|
438
|
+
struct _Options copts = oj_default_options;
|
439
|
+
VALUE rstr;
|
439
440
|
|
440
441
|
if (0 == (json = oj_write_obj_to_str(*argv, &copts))) {
|
441
|
-
|
442
|
+
rb_raise(rb_eNoMemError, "Not enough memory.\n");
|
442
443
|
}
|
443
444
|
rstr = rb_str_new2(json);
|
444
|
-
#
|
445
|
+
#if HAS_ENCODING_SUPPORT
|
445
446
|
rb_enc_associate(rstr, oj_utf8_encoding);
|
446
447
|
#endif
|
447
448
|
if (2 <= argc && Qnil != argv[1]) {
|
@@ -482,13 +483,13 @@ mimic_walk(VALUE key, VALUE obj, VALUE proc) {
|
|
482
483
|
rb_yield(obj);
|
483
484
|
}
|
484
485
|
} else {
|
485
|
-
#
|
486
|
-
rb_raise(rb_eNotImpError, "Not supported in Rubinius.\n");
|
487
|
-
#else
|
486
|
+
#if HAS_PROC_WITH_BLOCK
|
488
487
|
VALUE args[1];
|
489
488
|
|
490
489
|
*args = obj;
|
491
490
|
rb_proc_call_with_block(proc, 1, args, Qnil);
|
491
|
+
#else
|
492
|
+
rb_raise(rb_eNotImpError, "Calling a Proc with a block not supported in this version. Use func() {|x| } syntax instead.\n");
|
492
493
|
#endif
|
493
494
|
}
|
494
495
|
return ST_CONTINUE;
|
@@ -510,7 +511,7 @@ mimic_load(int argc, VALUE *argv, VALUE self) {
|
|
510
511
|
static VALUE
|
511
512
|
mimic_dump_load(int argc, VALUE *argv, VALUE self) {
|
512
513
|
if (1 > argc) {
|
513
|
-
|
514
|
+
rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)\n");
|
514
515
|
} else if (T_STRING == rb_type(*argv)) {
|
515
516
|
return mimic_load(argc, argv, self);
|
516
517
|
} else {
|
@@ -520,19 +521,19 @@ mimic_dump_load(int argc, VALUE *argv, VALUE self) {
|
|
520
521
|
|
521
522
|
static VALUE
|
522
523
|
mimic_generate_core(int argc, VALUE *argv, Options copts) {
|
523
|
-
char
|
524
|
-
VALUE
|
524
|
+
char *json;
|
525
|
+
VALUE rstr;
|
525
526
|
|
526
527
|
if (2 == argc && Qnil != argv[1]) {
|
527
528
|
struct _DumpOpts dump_opts;
|
528
529
|
VALUE ropts = argv[1];
|
529
|
-
|
530
|
+
VALUE v;
|
530
531
|
|
531
532
|
memset(&dump_opts, 0, sizeof(dump_opts)); // may not be needed
|
532
533
|
if (T_HASH != rb_type(ropts)) {
|
533
534
|
rb_raise(rb_eArgError, "options must be a hash.\n");
|
534
535
|
}
|
535
|
-
|
536
|
+
if (Qnil != (v = rb_hash_lookup(ropts, indent_sym))) {
|
536
537
|
rb_check_type(v, T_STRING);
|
537
538
|
if (0 == copts->dump_opts) {
|
538
539
|
copts->dump_opts = &dump_opts;
|
@@ -540,7 +541,7 @@ mimic_generate_core(int argc, VALUE *argv, Options copts) {
|
|
540
541
|
copts->dump_opts->indent = StringValuePtr(v);
|
541
542
|
copts->dump_opts->indent_size = (uint8_t)strlen(copts->dump_opts->indent);
|
542
543
|
}
|
543
|
-
|
544
|
+
if (Qnil != (v = rb_hash_lookup(ropts, space_sym))) {
|
544
545
|
rb_check_type(v, T_STRING);
|
545
546
|
if (0 == copts->dump_opts) {
|
546
547
|
copts->dump_opts = &dump_opts;
|
@@ -548,7 +549,7 @@ mimic_generate_core(int argc, VALUE *argv, Options copts) {
|
|
548
549
|
copts->dump_opts->after_sep = StringValuePtr(v);
|
549
550
|
copts->dump_opts->after_size = (uint8_t)strlen(copts->dump_opts->after_sep);
|
550
551
|
}
|
551
|
-
|
552
|
+
if (Qnil != (v = rb_hash_lookup(ropts, space_before_sym))) {
|
552
553
|
rb_check_type(v, T_STRING);
|
553
554
|
if (0 == copts->dump_opts) {
|
554
555
|
copts->dump_opts = &dump_opts;
|
@@ -556,7 +557,7 @@ mimic_generate_core(int argc, VALUE *argv, Options copts) {
|
|
556
557
|
copts->dump_opts->before_sep = StringValuePtr(v);
|
557
558
|
copts->dump_opts->before_size = (uint8_t)strlen(copts->dump_opts->before_sep);
|
558
559
|
}
|
559
|
-
|
560
|
+
if (Qnil != (v = rb_hash_lookup(ropts, object_nl_sym))) {
|
560
561
|
rb_check_type(v, T_STRING);
|
561
562
|
if (0 == copts->dump_opts) {
|
562
563
|
copts->dump_opts = &dump_opts;
|
@@ -564,7 +565,7 @@ mimic_generate_core(int argc, VALUE *argv, Options copts) {
|
|
564
565
|
copts->dump_opts->hash_nl = StringValuePtr(v);
|
565
566
|
copts->dump_opts->hash_size = (uint8_t)strlen(copts->dump_opts->hash_nl);
|
566
567
|
}
|
567
|
-
|
568
|
+
if (Qnil != (v = rb_hash_lookup(ropts, array_nl_sym))) {
|
568
569
|
rb_check_type(v, T_STRING);
|
569
570
|
if (0 == copts->dump_opts) {
|
570
571
|
copts->dump_opts = &dump_opts;
|
@@ -576,10 +577,10 @@ mimic_generate_core(int argc, VALUE *argv, Options copts) {
|
|
576
577
|
// :max_nesting is always set to 100
|
577
578
|
}
|
578
579
|
if (0 == (json = oj_write_obj_to_str(*argv, copts))) {
|
579
|
-
|
580
|
+
rb_raise(rb_eNoMemError, "Not enough memory.\n");
|
580
581
|
}
|
581
582
|
rstr = rb_str_new2(json);
|
582
|
-
#
|
583
|
+
#if HAS_ENCODING_SUPPORT
|
583
584
|
rb_enc_associate(rstr, oj_utf8_encoding);
|
584
585
|
#endif
|
585
586
|
xfree(json);
|
@@ -589,14 +590,14 @@ mimic_generate_core(int argc, VALUE *argv, Options copts) {
|
|
589
590
|
|
590
591
|
static VALUE
|
591
592
|
mimic_generate(int argc, VALUE *argv, VALUE self) {
|
592
|
-
struct _Options
|
593
|
+
struct _Options copts = oj_default_options;
|
593
594
|
|
594
595
|
return mimic_generate_core(argc, argv, &copts);
|
595
596
|
}
|
596
597
|
|
597
598
|
static VALUE
|
598
599
|
mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
|
599
|
-
struct _Options
|
600
|
+
struct _Options copts = oj_default_options;
|
600
601
|
struct _DumpOpts dump_opts;
|
601
602
|
|
602
603
|
dump_opts.indent = " ";
|
@@ -623,15 +624,15 @@ mimic_parse(int argc, VALUE *argv, VALUE self) {
|
|
623
624
|
}
|
624
625
|
if (2 <= argc && Qnil != argv[1]) {
|
625
626
|
VALUE ropts = argv[1];
|
626
|
-
|
627
|
+
VALUE v;
|
627
628
|
|
628
629
|
if (T_HASH != rb_type(ropts)) {
|
629
630
|
rb_raise(rb_eArgError, "options must be a hash.\n");
|
630
631
|
}
|
631
|
-
|
632
|
+
if (Qnil != (v = rb_hash_lookup(ropts, symbolize_names_sym))) {
|
632
633
|
options.sym_key = (Qtrue == v) ? Yes : No;
|
633
634
|
}
|
634
|
-
|
635
|
+
if (Qnil != (v = rb_hash_lookup(ropts, create_additions_sym))) {
|
635
636
|
options.mode = (Qtrue == v) ? CompatMode : StrictMode;
|
636
637
|
}
|
637
638
|
// :allow_nan is not supported as Oj always allows_nan
|
@@ -729,6 +730,7 @@ void Init_oj() {
|
|
729
730
|
oj_write_id = rb_intern("write");
|
730
731
|
oj_tv_nsec_id = rb_intern("tv_nsec");
|
731
732
|
oj_tv_sec_id = rb_intern("tv_sec");
|
733
|
+
oj_tv_usec_id = rb_intern("tv_usec");
|
732
734
|
|
733
735
|
oj_bag_class = rb_const_get_at(Oj, rb_intern("Bag"));
|
734
736
|
oj_struct_class = rb_const_get(rb_cObject, rb_intern("Struct"));
|
@@ -750,7 +752,7 @@ void Init_oj() {
|
|
750
752
|
oj_slash_string = rb_str_new2("/"); rb_ary_push(keep, oj_slash_string);
|
751
753
|
|
752
754
|
oj_default_options.mode = ObjectMode;
|
753
|
-
#
|
755
|
+
#if HAS_ENCODING_SUPPORT
|
754
756
|
oj_utf8_encoding = rb_enc_find("UTF-8");
|
755
757
|
#endif
|
756
758
|
|
@@ -762,16 +764,17 @@ void Init_oj() {
|
|
762
764
|
|
763
765
|
void
|
764
766
|
_oj_raise_error(const char *msg, const char *xml, const char *current, const char* file, int line) {
|
765
|
-
int
|
766
|
-
int
|
767
|
+
int xline = 1;
|
768
|
+
int col = 1;
|
767
769
|
|
768
770
|
for (; xml < current && '\n' != *current; current--) {
|
769
|
-
|
771
|
+
col++;
|
770
772
|
}
|
771
773
|
for (; xml < current; current--) {
|
772
|
-
|
773
|
-
|
774
|
-
|
774
|
+
if ('\n' == *current) {
|
775
|
+
xline++;
|
776
|
+
}
|
775
777
|
}
|
776
778
|
rb_raise(rb_eSyntaxError, "%s at line %d, column %d [%s:%d]\n", msg, xline, col, file, line);
|
777
779
|
}
|
780
|
+
|