Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F4439394
util.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
45 KB
Referenced Files
None
Subscribers
None
util.c
View Options
// TODO: split module into smaller files
#include
<compat.h>
// IWYU pragma: keep
#include
<ctype.h>
#include
<math.h>
#include
<stdbool.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
"ant.h"
#include
"internal.h"
#include
"esm/library.h"
#include
"silver/engine.h"
#include
"modules/buffer.h"
#include
"modules/date.h"
#include
"modules/json.h"
#include
"modules/symbol.h"
#include
"modules/util.h"
#include
"modules/abort.h"
#include
"modules/collections.h"
typedef
struct
{
char
*
buf
;
size_t
len
;
size_t
cap
;
}
util_sb_t
;
typedef
struct
{
const
char
*
name
;
const
char
*
open
;
const
char
*
close
;
}
util_style_entry_t
;
typedef
enum
{
UTIL_PARSE_ARG_TYPE_BOOLEAN
=
0
,
UTIL_PARSE_ARG_TYPE_STRING
,
}
util_parse_arg_type_t
;
typedef
struct
{
char
*
name
;
char
short_name
;
util_parse_arg_type_t
type
;
bool
multiple
;
ant_value_t
default_value
;
}
util_parse_arg_option_t
;
// TODO: migrate to crprintf
static
const
util_style_entry_t
util_styles
[]
=
{
{
"bold"
,
"
\x1b
[1m"
,
"
\x1b
[22m"
},
{
"dim"
,
"
\x1b
[2m"
,
"
\x1b
[22m"
},
{
"italic"
,
"
\x1b
[3m"
,
"
\x1b
[23m"
},
{
"underline"
,
"
\x1b
[4m"
,
"
\x1b
[24m"
},
{
"inverse"
,
"
\x1b
[7m"
,
"
\x1b
[27m"
},
{
"hidden"
,
"
\x1b
[8m"
,
"
\x1b
[28m"
},
{
"strikethrough"
,
"
\x1b
[9m"
,
"
\x1b
[29m"
},
{
"black"
,
"
\x1b
[30m"
,
"
\x1b
[39m"
},
{
"red"
,
"
\x1b
[31m"
,
"
\x1b
[39m"
},
{
"green"
,
"
\x1b
[32m"
,
"
\x1b
[39m"
},
{
"yellow"
,
"
\x1b
[33m"
,
"
\x1b
[39m"
},
{
"blue"
,
"
\x1b
[34m"
,
"
\x1b
[39m"
},
{
"magenta"
,
"
\x1b
[35m"
,
"
\x1b
[39m"
},
{
"cyan"
,
"
\x1b
[36m"
,
"
\x1b
[39m"
},
{
"white"
,
"
\x1b
[37m"
,
"
\x1b
[39m"
},
{
"gray"
,
"
\x1b
[90m"
,
"
\x1b
[39m"
},
{
"grey"
,
"
\x1b
[90m"
,
"
\x1b
[39m"
},
{
"bgBlack"
,
"
\x1b
[40m"
,
"
\x1b
[49m"
},
{
"bgRed"
,
"
\x1b
[41m"
,
"
\x1b
[49m"
},
{
"bgGreen"
,
"
\x1b
[42m"
,
"
\x1b
[49m"
},
{
"bgYellow"
,
"
\x1b
[43m"
,
"
\x1b
[49m"
},
{
"bgBlue"
,
"
\x1b
[44m"
,
"
\x1b
[49m"
},
{
"bgMagenta"
,
"
\x1b
[45m"
,
"
\x1b
[49m"
},
{
"bgCyan"
,
"
\x1b
[46m"
,
"
\x1b
[49m"
},
{
"bgWhite"
,
"
\x1b
[47m"
,
"
\x1b
[49m"
},
};
static
bool
util_sb_reserve
(
util_sb_t
*
sb
,
size_t
extra
)
{
size_t
need
=
sb
->
len
+
extra
+
1
;
if
(
need
<=
sb
->
cap
)
return
true
;
size_t
next
=
sb
->
cap
?
sb
->
cap
:
128
;
while
(
next
<
need
)
next
*=
2
;
char
*
buf
=
(
char
*
)
realloc
(
sb
->
buf
,
next
);
if
(
!
buf
)
return
false
;
sb
->
buf
=
buf
;
sb
->
cap
=
next
;
return
true
;
}
static
bool
util_sb_append_n
(
util_sb_t
*
sb
,
const
char
*
s
,
size_t
n
)
{
if
(
n
==
0
)
return
true
;
if
(
!
util_sb_reserve
(
sb
,
n
))
return
false
;
memcpy
(
sb
->
buf
+
sb
->
len
,
s
,
n
);
sb
->
len
+=
n
;
sb
->
buf
[
sb
->
len
]
=
'\0'
;
return
true
;
}
static
bool
util_sb_append_c
(
util_sb_t
*
sb
,
char
c
)
{
if
(
!
util_sb_reserve
(
sb
,
1
))
return
false
;
sb
->
buf
[
sb
->
len
++
]
=
c
;
sb
->
buf
[
sb
->
len
]
=
'\0'
;
return
true
;
}
static
bool
util_sb_append_jsval
(
ant_t
*
js
,
util_sb_t
*
sb
,
ant_value_t
v
)
{
char
cbuf
[
512
];
js_cstr_t
cstr
=
js_to_cstr
(
js
,
v
,
cbuf
,
sizeof
(
cbuf
));
size_t
len
=
strlen
(
cstr
.
ptr
);
bool
ok
=
util_sb_append_n
(
sb
,
cstr
.
ptr
,
len
);
if
(
cstr
.
needs_free
)
free
((
void
*
)
cstr
.
ptr
);
return
ok
;
}
static
bool
util_sb_append_json
(
ant_t
*
js
,
util_sb_t
*
sb
,
ant_value_t
v
)
{
ant_value_t
json
=
json_stringify_value
(
js
,
v
);
if
(
vtype
(
json
)
!=
T_STR
)
{
return
util_sb_append_n
(
sb
,
"[Circular]"
,
10
);
}
size_t
len
=
0
;
const
char
*
s
=
js_getstr
(
js
,
json
,
&
len
);
return
s
?
util_sb_append_n
(
sb
,
s
,
len
)
:
util_sb_append_n
(
sb
,
"[Circular]"
,
10
);
}
static
bool
util_set_named_value
(
ant_t
*
js
,
ant_value_t
values
,
const
char
*
name
,
ant_value_t
value
,
bool
multiple
)
{
if
(
!
multiple
)
{
js_set
(
js
,
values
,
name
,
value
);
return
!
js
->
thrown_exists
;
}
ant_value_t
existing
=
js_get
(
js
,
values
,
name
);
if
(
is_err
(
existing
))
return
false
;
if
(
vtype
(
existing
)
==
T_UNDEF
)
{
ant_value_t
arr
=
js_mkarr
(
js
);
js_arr_push
(
js
,
arr
,
value
);
js_set
(
js
,
values
,
name
,
arr
);
return
!
js
->
thrown_exists
;
}
if
(
vtype
(
existing
)
==
T_ARR
)
{
js_arr_push
(
js
,
existing
,
value
);
return
!
js
->
thrown_exists
;
}
ant_value_t
arr
=
js_mkarr
(
js
);
js_arr_push
(
js
,
arr
,
existing
);
js_arr_push
(
js
,
arr
,
value
);
js_set
(
js
,
values
,
name
,
arr
);
return
!
js
->
thrown_exists
;
}
static
util_parse_arg_option_t
*
util_find_option_by_name
(
util_parse_arg_option_t
*
options
,
size_t
option_count
,
const
char
*
name
)
{
for
(
size_t
i
=
0
;
i
<
option_count
;
i
++
)
{
if
(
strcmp
(
options
[
i
].
name
,
name
)
==
0
)
return
&
options
[
i
];
}
return
NULL
;
}
static
util_parse_arg_option_t
*
util_find_option_by_short
(
util_parse_arg_option_t
*
options
,
size_t
option_count
,
char
short_name
)
{
for
(
size_t
i
=
0
;
i
<
option_count
;
i
++
)
{
if
(
options
[
i
].
short_name
==
short_name
)
return
&
options
[
i
];
}
return
NULL
;
}
static
void
util_free_parse_options
(
util_parse_arg_option_t
*
options
,
size_t
option_count
)
{
if
(
!
options
)
return
;
for
(
size_t
i
=
0
;
i
<
option_count
;
i
++
)
free
(
options
[
i
].
name
);
free
(
options
);
}
static
ant_value_t
util_parse_args
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
config
=
nargs
>
0
?
args
[
0
]
:
js_mkundef
();
if
(
!
is_object_type
(
config
))
{
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"parseArgs(config) requires an options object"
);
}
ant_value_t
args_list
=
js_get
(
js
,
config
,
"args"
);
if
(
is_err
(
args_list
))
return
args_list
;
if
(
vtype
(
args_list
)
==
T_UNDEF
)
{
ant_value_t
process_obj
=
js_get
(
js
,
js_glob
(
js
),
"process"
);
if
(
is_err
(
process_obj
))
return
process_obj
;
args_list
=
js_get
(
js
,
process_obj
,
"argv"
);
if
(
is_err
(
args_list
))
return
args_list
;
}
ant_value_t
options_obj
=
js_get
(
js
,
config
,
"options"
);
if
(
is_err
(
options_obj
))
return
options_obj
;
if
(
!
is_object_type
(
options_obj
))
options_obj
=
js_mkobj
(
js
);
bool
strict
=
js_truthy
(
js
,
js_get
(
js
,
config
,
"strict"
));
if
(
vtype
(
js_get
(
js
,
config
,
"strict"
))
==
T_UNDEF
)
strict
=
true
;
bool
allow_positionals
=
js_truthy
(
js
,
js_get
(
js
,
config
,
"allowPositionals"
));
size_t
option_count
=
0
;
{
ant_iter_t
iter
=
js_prop_iter_begin
(
js
,
options_obj
);
const
char
*
key
=
NULL
;
size_t
key_len
=
0
;
while
(
js_prop_iter_next
(
&
iter
,
&
key
,
&
key_len
,
NULL
))
option_count
++
;
js_prop_iter_end
(
&
iter
);
}
util_parse_arg_option_t
*
options
=
NULL
;
if
(
option_count
>
0
)
{
options
=
calloc
(
option_count
,
sizeof
(
*
options
));
if
(
!
options
)
return
js_mkerr
(
js
,
"Out of memory"
);
ant_iter_t
iter
=
js_prop_iter_begin
(
js
,
options_obj
);
const
char
*
key
=
NULL
;
size_t
key_len
=
0
;
size_t
idx
=
0
;
while
(
idx
<
option_count
&&
js_prop_iter_next
(
&
iter
,
&
key
,
&
key_len
,
NULL
))
{
ant_value_t
spec
=
js_get
(
js
,
options_obj
,
key
);
ant_value_t
type_val
=
is_object_type
(
spec
)
?
js_get
(
js
,
spec
,
"type"
)
:
js_mkundef
();
ant_value_t
short_val
=
is_object_type
(
spec
)
?
js_get
(
js
,
spec
,
"short"
)
:
js_mkundef
();
ant_value_t
multiple_val
=
is_object_type
(
spec
)
?
js_get
(
js
,
spec
,
"multiple"
)
:
js_mkundef
();
ant_value_t
default_val
=
is_object_type
(
spec
)
?
js_get
(
js
,
spec
,
"default"
)
:
js_mkundef
();
options
[
idx
].
name
=
strndup
(
key
,
key_len
);
if
(
!
options
[
idx
].
name
)
{
js_prop_iter_end
(
&
iter
);
util_free_parse_options
(
options
,
option_count
);
return
js_mkerr
(
js
,
"Out of memory"
);
}
options
[
idx
].
type
=
UTIL_PARSE_ARG_TYPE_BOOLEAN
;
if
(
vtype
(
type_val
)
==
T_STR
)
{
size_t
type_len
=
0
;
const
char
*
type_str
=
js_getstr
(
js
,
type_val
,
&
type_len
);
if
(
type_str
&&
type_len
==
6
&&
memcmp
(
type_str
,
"string"
,
6
)
==
0
)
{
options
[
idx
].
type
=
UTIL_PARSE_ARG_TYPE_STRING
;
}
}
if
(
vtype
(
short_val
)
==
T_STR
)
{
size_t
short_len
=
0
;
const
char
*
short_str
=
js_getstr
(
js
,
short_val
,
&
short_len
);
if
(
short_str
&&
short_len
>
0
)
options
[
idx
].
short_name
=
short_str
[
0
];
}
options
[
idx
].
multiple
=
js_truthy
(
js
,
multiple_val
);
options
[
idx
].
default_value
=
default_val
;
idx
++
;
}
js_prop_iter_end
(
&
iter
);
}
ant_value_t
values
=
js_mkobj
(
js
);
ant_value_t
positionals
=
js_mkarr
(
js
);
ant_value_t
out
=
js_mkobj
(
js
);
for
(
size_t
i
=
0
;
i
<
option_count
;
i
++
)
{
if
(
vtype
(
options
[
i
].
default_value
)
!=
T_UNDEF
)
{
if
(
!
util_set_named_value
(
js
,
values
,
options
[
i
].
name
,
options
[
i
].
default_value
,
options
[
i
].
multiple
))
{
util_free_parse_options
(
options
,
option_count
);
return
js
->
thrown_exists
?
js
->
thrown_value
:
js_mkerr
(
js
,
"parseArgs failed to set default"
);
}}}
ant_offset_t
arg_len
=
js_arr_len
(
js
,
args_list
);
bool
stop_parsing
=
false
;
for
(
ant_offset_t
i
=
0
;
i
<
arg_len
;
i
++
)
{
ant_value_t
arg_val
=
js_arr_get
(
js
,
args_list
,
i
);
if
(
vtype
(
arg_val
)
!=
T_STR
)
continue
;
size_t
arg_slen
=
0
;
const
char
*
arg
=
js_getstr
(
js
,
arg_val
,
&
arg_slen
);
if
(
!
arg
)
continue
;
if
(
stop_parsing
)
{
js_arr_push
(
js
,
positionals
,
arg_val
);
continue
;
}
if
(
arg_slen
==
2
&&
memcmp
(
arg
,
"--"
,
2
)
==
0
)
{
stop_parsing
=
true
;
continue
;
}
if
(
arg_slen
>
2
&&
arg
[
0
]
==
'-'
&&
arg
[
1
]
==
'-'
)
{
const
char
*
name
=
arg
+
2
;
size_t
name_len
=
arg_slen
-
2
;
const
char
*
inline_value
=
NULL
;
size_t
inline_len
=
0
;
const
char
*
eq
=
memchr
(
name
,
'='
,
name_len
);
if
(
eq
)
{
name_len
=
(
size_t
)(
eq
-
name
);
inline_value
=
eq
+
1
;
inline_len
=
(
size_t
)(
arg
+
arg_slen
-
inline_value
);
}
char
*
name_buf
=
strndup
(
name
,
name_len
);
if
(
!
name_buf
)
{
util_free_parse_options
(
options
,
option_count
);
return
js_mkerr
(
js
,
"Out of memory"
);
}
util_parse_arg_option_t
*
opt
=
util_find_option_by_name
(
options
,
option_count
,
name_buf
);
if
(
!
opt
)
{
if
(
strict
)
{
free
(
name_buf
);
util_free_parse_options
(
options
,
option_count
);
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"Unknown option '--%.*s'"
,
(
int
)
name_len
,
name
);
}
ant_value_t
unknown
=
inline_value
?
js_mkstr
(
js
,
inline_value
,
inline_len
)
:
js_true
;
js_set
(
js
,
values
,
name_buf
,
unknown
);
free
(
name_buf
);
continue
;
}
ant_value_t
parsed_value
=
js_true
;
if
(
opt
->
type
==
UTIL_PARSE_ARG_TYPE_STRING
)
{
if
(
inline_value
)
parsed_value
=
js_mkstr
(
js
,
inline_value
,
inline_len
);
else
if
(
i
+
1
<
arg_len
)
parsed_value
=
js_arr_get
(
js
,
args_list
,
++
i
);
else
{
free
(
name_buf
);
util_free_parse_options
(
options
,
option_count
);
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"Option '--%s' requires a value"
,
opt
->
name
);
}
}
else
if
(
inline_value
)
parsed_value
=
js_mkstr
(
js
,
inline_value
,
inline_len
);
if
(
!
util_set_named_value
(
js
,
values
,
opt
->
name
,
parsed_value
,
opt
->
multiple
))
{
free
(
name_buf
);
util_free_parse_options
(
options
,
option_count
);
return
js
->
thrown_exists
?
js
->
thrown_value
:
js_mkerr
(
js
,
"parseArgs failed"
);
}
free
(
name_buf
);
continue
;
}
if
(
arg_slen
>
1
&&
arg
[
0
]
==
'-'
)
{
for
(
size_t
j
=
1
;
j
<
arg_slen
;
j
++
)
{
util_parse_arg_option_t
*
opt
=
util_find_option_by_short
(
options
,
option_count
,
arg
[
j
]);
if
(
!
opt
)
{
if
(
strict
)
{
util_free_parse_options
(
options
,
option_count
);
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"Unknown option '-%c'"
,
arg
[
j
]);
}
char
key
[
2
]
=
{
arg
[
j
],
'\0'
};
js_set
(
js
,
values
,
key
,
js_true
);
continue
;
}
ant_value_t
parsed_value
=
js_true
;
if
(
opt
->
type
==
UTIL_PARSE_ARG_TYPE_STRING
)
{
if
(
j
+
1
<
arg_slen
)
{
parsed_value
=
js_mkstr
(
js
,
arg
+
j
+
1
,
arg_slen
-
(
j
+
1
));
j
=
arg_slen
;
}
else
if
(
i
+
1
<
arg_len
)
{
parsed_value
=
js_arr_get
(
js
,
args_list
,
++
i
);
j
=
arg_slen
;
}
else
{
util_free_parse_options
(
options
,
option_count
);
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"Option '-%c' requires a value"
,
arg
[
j
]);
}
}
if
(
!
util_set_named_value
(
js
,
values
,
opt
->
name
,
parsed_value
,
opt
->
multiple
))
{
util_free_parse_options
(
options
,
option_count
);
return
js
->
thrown_exists
?
js
->
thrown_value
:
js_mkerr
(
js
,
"parseArgs failed"
);
}
if
(
opt
->
type
==
UTIL_PARSE_ARG_TYPE_STRING
)
break
;
}
continue
;
}
if
(
!
allow_positionals
)
{
util_free_parse_options
(
options
,
option_count
);
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"Unexpected positional argument '%s'"
,
arg
);
}
js_arr_push
(
js
,
positionals
,
arg_val
);
}
util_free_parse_options
(
options
,
option_count
);
js_set
(
js
,
out
,
"values"
,
values
);
js_set
(
js
,
out
,
"positionals"
,
positionals
);
return
out
;
}
static
ant_value_t
util_format_impl
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
,
int
fmt_index
)
{
util_sb_t
sb
=
{
0
};
if
(
fmt_index
>=
nargs
)
{
ant_value_t
out
=
js_mkstr
(
js
,
""
,
0
);
free
(
sb
.
buf
);
return
out
;
}
if
(
vtype
(
args
[
fmt_index
])
!=
T_STR
)
{
for
(
int
i
=
fmt_index
;
i
<
nargs
;
i
++
)
{
if
(
i
>
fmt_index
)
util_sb_append_c
(
&
sb
,
' '
);
util_sb_append_jsval
(
js
,
&
sb
,
args
[
i
]);
}
ant_value_t
out
=
js_mkstr
(
js
,
sb
.
buf
?
sb
.
buf
:
""
,
sb
.
len
);
free
(
sb
.
buf
);
return
out
;
}
size_t
fmt_len
=
0
;
const
char
*
fmt
=
js_getstr
(
js
,
args
[
fmt_index
],
&
fmt_len
);
int
argi
=
fmt_index
+
1
;
for
(
size_t
i
=
0
;
i
<
fmt_len
;
i
++
)
{
if
(
fmt
[
i
]
!=
'%'
||
i
+
1
>=
fmt_len
)
{
util_sb_append_c
(
&
sb
,
fmt
[
i
]);
continue
;
}
char
spec
=
fmt
[
i
+
1
];
if
(
spec
==
'%'
)
{
util_sb_append_c
(
&
sb
,
'%'
);
i
++
;
continue
;
}
bool
known
=
(
spec
==
's'
||
spec
==
'd'
||
spec
==
'i'
||
spec
==
'f'
||
spec
==
'j'
||
spec
==
'o'
||
spec
==
'O'
||
spec
==
'c'
);
if
(
!
known
)
{
util_sb_append_c
(
&
sb
,
'%'
);
util_sb_append_c
(
&
sb
,
spec
);
i
++
;
continue
;
}
ant_value_t
v
=
(
argi
<
nargs
)
?
args
[
argi
++
]
:
js_mkundef
();
if
(
spec
==
's'
)
{
util_sb_append_jsval
(
js
,
&
sb
,
v
);
}
else
if
(
spec
==
'd'
||
spec
==
'i'
)
{
double
d
=
js_to_number
(
js
,
v
);
char
nb
[
64
];
if
(
isnan
(
d
))
snprintf
(
nb
,
sizeof
(
nb
),
"NaN"
);
else
if
(
!
isfinite
(
d
))
snprintf
(
nb
,
sizeof
(
nb
),
d
<
0
?
"-Infinity"
:
"Infinity"
);
else
snprintf
(
nb
,
sizeof
(
nb
),
"%lld"
,
(
long
long
)
d
);
util_sb_append_n
(
&
sb
,
nb
,
strlen
(
nb
));
}
else
if
(
spec
==
'f'
)
{
double
d
=
js_to_number
(
js
,
v
);
char
nb
[
64
];
if
(
isnan
(
d
))
snprintf
(
nb
,
sizeof
(
nb
),
"NaN"
);
else
if
(
!
isfinite
(
d
))
snprintf
(
nb
,
sizeof
(
nb
),
d
<
0
?
"-Infinity"
:
"Infinity"
);
else
snprintf
(
nb
,
sizeof
(
nb
),
"%g"
,
d
);
util_sb_append_n
(
&
sb
,
nb
,
strlen
(
nb
));
}
else
if
(
spec
==
'j'
)
{
util_sb_append_json
(
js
,
&
sb
,
v
);
}
else
if
(
spec
==
'o'
||
spec
==
'O'
)
{
util_sb_append_jsval
(
js
,
&
sb
,
v
);
}
else
if
(
spec
==
'c'
)
{
// style placeholder: consume arg, emit nothing.
}
i
++
;
}
for
(;
argi
<
nargs
;
argi
++
)
{
util_sb_append_c
(
&
sb
,
' '
);
util_sb_append_jsval
(
js
,
&
sb
,
args
[
argi
]);
}
ant_value_t
out
=
js_mkstr
(
js
,
sb
.
buf
?
sb
.
buf
:
""
,
sb
.
len
);
free
(
sb
.
buf
);
return
out
;
}
static
ant_value_t
util_format
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
util_format_impl
(
js
,
args
,
nargs
,
0
);
}
static
ant_value_t
util_format_with_options
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<=
1
)
return
js_mkstr
(
js
,
""
,
0
);
return
util_format_impl
(
js
,
args
,
nargs
,
1
);
}
static
ant_value_t
util_inspect
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkstr
(
js
,
"undefined"
,
9
);
char
cbuf
[
512
];
js_cstr_t
cstr
=
js_to_cstr
(
js
,
args
[
0
],
cbuf
,
sizeof
(
cbuf
));
ant_value_t
out
=
js_mkstr
(
js
,
cstr
.
ptr
,
strlen
(
cstr
.
ptr
));
if
(
cstr
.
needs_free
)
free
((
void
*
)
cstr
.
ptr
);
return
out
;
}
static
bool
util_has_proto_in_chain
(
ant_t
*
js
,
ant_value_t
value
,
ant_value_t
proto
)
{
if
(
!
is_special_object
(
proto
))
return
false
;
ant_value_t
current
=
value
;
while
(
is_special_object
(
current
))
{
current
=
js_get_proto
(
js
,
current
);
if
(
current
==
proto
)
return
true
;
}
return
false
;
}
static
bool
util_is_boxed_primitive
(
ant_value_t
value
,
uint8_t
*
type_out
)
{
ant_value_t
primitive
;
if
(
!
is_object_type
(
value
))
return
false
;
primitive
=
js_get_slot
(
value
,
SLOT_PRIMITIVE
);
if
(
vtype
(
primitive
)
==
T_UNDEF
)
return
false
;
if
(
type_out
)
*
type_out
=
vtype
(
primitive
);
return
true
;
}
static
bool
util_has_to_string_tag
(
ant_t
*
js
,
ant_value_t
value
,
const
char
*
tag
,
size_t
tag_len
)
{
ant_value_t
to_string_tag
;
size_t
actual_len
=
0
;
const
char
*
actual
;
if
(
!
is_object_type
(
value
))
return
false
;
to_string_tag
=
js_get_sym
(
js
,
value
,
get_toStringTag_sym
());
if
(
vtype
(
to_string_tag
)
!=
T_STR
)
return
false
;
actual
=
js_getstr
(
js
,
to_string_tag
,
&
actual_len
);
return
actual
!=
NULL
&&
actual_len
==
tag_len
&&
memcmp
(
actual
,
tag
,
tag_len
)
==
0
;
}
static
bool
util_is_arguments_object_value
(
ant_t
*
js
,
ant_value_t
value
)
{
ant_value_t
callee
=
js_mkundef
();
if
(
vtype
(
value
)
!=
T_ARR
)
return
false
;
if
(
js_get_slot
(
value
,
SLOT_STRICT_ARGS
)
==
js_true
)
return
true
;
if
(
!
util_has_to_string_tag
(
js
,
value
,
"Arguments"
,
9
))
return
false
;
return
js_try_get_own_data_prop
(
js
,
value
,
"callee"
,
6
,
&
callee
);
}
static
ant_value_t
util_types_is_any_array_buffer
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ArrayBufferData
*
buffer
=
(
nargs
>
0
)
?
buffer_get_arraybuffer_data
(
args
[
0
])
:
NULL
;
return
js_bool
(
buffer
!=
NULL
);
}
static
ant_value_t
util_types_is_array_buffer
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ArrayBufferData
*
buffer
=
(
nargs
>
0
)
?
buffer_get_arraybuffer_data
(
args
[
0
])
:
NULL
;
return
js_bool
(
buffer
!=
NULL
&&
!
buffer
->
is_shared
);
}
static
ant_value_t
util_types_is_shared_array_buffer
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ArrayBufferData
*
buffer
=
(
nargs
>
0
)
?
buffer_get_arraybuffer_data
(
args
[
0
])
:
NULL
;
return
js_bool
(
buffer
!=
NULL
&&
buffer
->
is_shared
);
}
static
ant_value_t
util_types_is_array_buffer_view
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_false
;
return
js_bool
(
buffer_is_dataview
(
args
[
0
])
||
buffer_get_typedarray_data
(
args
[
0
])
!=
NULL
);
}
static
ant_value_t
util_types_is_data_view
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_false
;
return
js_bool
(
buffer_is_dataview
(
args
[
0
]));
}
static
ant_value_t
util_types_is_typed_array
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_false
;
return
js_bool
(
buffer_get_typedarray_data
(
args
[
0
])
!=
NULL
);
}
static
ant_value_t
util_types_is_float16_array
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
TypedArrayData
*
typed_array
=
(
nargs
>
0
)
?
buffer_get_typedarray_data
(
args
[
0
])
:
NULL
;
if
(
!
typed_array
)
return
js_false
;
return
js_bool
(
typed_array
!=
NULL
&&
typed_array
->
type
==
TYPED_ARRAY_FLOAT16
);
}
#define DEFINE_TYPED_ARRAY_CHECK(fn_name, typed_array_kind) \
static ant_value_t fn_name(ant_t *js, ant_value_t *args, int nargs) { \
TypedArrayData *typed_array = (nargs > 0) ? buffer_get_typedarray_data(args[0]) : NULL; \
if (!typed_array) return js_false; \
return js_bool(typed_array != NULL && typed_array->type == typed_array_kind); \
}
DEFINE_TYPED_ARRAY_CHECK
(
util_types_is_int8_array
,
TYPED_ARRAY_INT8
)
DEFINE_TYPED_ARRAY_CHECK
(
util_types_is_uint8_array
,
TYPED_ARRAY_UINT8
)
DEFINE_TYPED_ARRAY_CHECK
(
util_types_is_int16_array
,
TYPED_ARRAY_INT16
)
DEFINE_TYPED_ARRAY_CHECK
(
util_types_is_uint16_array
,
TYPED_ARRAY_UINT16
)
DEFINE_TYPED_ARRAY_CHECK
(
util_types_is_int32_array
,
TYPED_ARRAY_INT32
)
DEFINE_TYPED_ARRAY_CHECK
(
util_types_is_uint32_array
,
TYPED_ARRAY_UINT32
)
DEFINE_TYPED_ARRAY_CHECK
(
util_types_is_float32_array
,
TYPED_ARRAY_FLOAT32
)
DEFINE_TYPED_ARRAY_CHECK
(
util_types_is_float64_array
,
TYPED_ARRAY_FLOAT64
)
DEFINE_TYPED_ARRAY_CHECK
(
util_types_is_bigint64_array
,
TYPED_ARRAY_BIGINT64
)
DEFINE_TYPED_ARRAY_CHECK
(
util_types_is_biguint64_array
,
TYPED_ARRAY_BIGUINT64
)
DEFINE_TYPED_ARRAY_CHECK
(
util_types_is_uint8_clamped_array
,
TYPED_ARRAY_UINT8_CLAMPED
)
static
ant_value_t
util_types_is_promise
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_false
;
return
js_bool
(
vtype
(
args
[
0
])
==
T_PROMISE
);
}
static
ant_value_t
util_types_is_proxy
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
!
is_object_type
(
args
[
0
]))
return
js_false
;
return
js_bool
(
is_proxy
(
args
[
0
]));
}
static
ant_value_t
util_types_is_regexp
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
regexp_proto
;
if
(
nargs
<
1
||
!
is_object_type
(
args
[
0
]))
return
js_false
;
regexp_proto
=
js_get_ctor_proto
(
js
,
"RegExp"
,
6
);
return
js_bool
(
util_has_proto_in_chain
(
js
,
args
[
0
],
regexp_proto
));
}
static
ant_value_t
util_types_is_date
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_false
;
return
js_bool
(
is_date_instance
(
args
[
0
]));
}
static
ant_value_t
util_types_is_map
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
vtype
(
args
[
0
])
!=
T_OBJ
)
return
js_false
;
return
js_bool
(
js_obj_ptr
(
args
[
0
])
->
type_tag
==
T_MAP
);
}
static
ant_value_t
util_types_is_set
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
vtype
(
args
[
0
])
!=
T_OBJ
)
return
js_false
;
return
js_bool
(
js_obj_ptr
(
args
[
0
])
->
type_tag
==
T_SET
);
}
static
ant_value_t
util_types_is_weak_map
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
vtype
(
args
[
0
])
!=
T_OBJ
)
return
js_false
;
return
js_bool
(
js_obj_ptr
(
args
[
0
])
->
type_tag
==
T_WEAKMAP
);
}
static
ant_value_t
util_types_is_weak_set
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
vtype
(
args
[
0
])
!=
T_OBJ
)
return
js_false
;
return
js_bool
(
js_obj_ptr
(
args
[
0
])
->
type_tag
==
T_WEAKSET
);
}
static
ant_value_t
util_types_is_async_function
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
func_obj
;
if
(
nargs
<
1
||
vtype
(
args
[
0
])
!=
T_FUNC
)
return
js_false
;
func_obj
=
js_func_obj
(
args
[
0
]);
return
js_bool
(
js_get_slot
(
func_obj
,
SLOT_ASYNC
)
==
js_true
);
}
static
ant_value_t
util_types_is_generator_function
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
sv_closure_t
*
closure
;
if
(
nargs
<
1
||
vtype
(
args
[
0
])
!=
T_FUNC
)
return
js_false
;
closure
=
js_func_closure
(
args
[
0
]);
return
js_bool
(
closure
!=
NULL
&&
closure
->
func
!=
NULL
&&
closure
->
func
->
is_generator
);
}
static
ant_value_t
util_types_is_generator_object
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_false
;
return
js_bool
(
vtype
(
args
[
0
])
==
T_GENERATOR
);
}
static
ant_value_t
util_types_is_arguments_object
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_false
;
return
js_bool
(
util_is_arguments_object_value
(
js
,
args
[
0
]));
}
static
ant_value_t
util_types_is_native_error
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
!
is_object_type
(
args
[
0
]))
return
js_false
;
return
js_bool
(
js_get_slot
(
args
[
0
],
SLOT_ERROR_BRAND
)
==
js_true
);
}
static
ant_value_t
util_types_is_boxed_primitive
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
js_bool
(
nargs
>
0
&&
util_is_boxed_primitive
(
args
[
0
],
NULL
));
}
static
ant_value_t
util_types_is_boolean_object
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
uint8_t
type
=
T_UNDEF
;
return
js_bool
(
nargs
>
0
&&
util_is_boxed_primitive
(
args
[
0
],
&
type
)
&&
type
==
T_BOOL
);
}
static
ant_value_t
util_types_is_number_object
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
uint8_t
type
=
T_UNDEF
;
return
js_bool
(
nargs
>
0
&&
util_is_boxed_primitive
(
args
[
0
],
&
type
)
&&
type
==
T_NUM
);
}
static
ant_value_t
util_types_is_string_object
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
uint8_t
type
=
T_UNDEF
;
return
js_bool
(
nargs
>
0
&&
util_is_boxed_primitive
(
args
[
0
],
&
type
)
&&
type
==
T_STR
);
}
static
ant_value_t
util_types_is_symbol_object
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
uint8_t
type
=
T_UNDEF
;
return
js_bool
(
nargs
>
0
&&
util_is_boxed_primitive
(
args
[
0
],
&
type
)
&&
type
==
T_SYMBOL
);
}
static
ant_value_t
util_types_is_bigint_object
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
uint8_t
type
=
T_UNDEF
;
return
js_bool
(
nargs
>
0
&&
util_is_boxed_primitive
(
args
[
0
],
&
type
)
&&
type
==
T_BIGINT
);
}
static
ant_value_t
util_types_is_map_iterator
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
!
is_object_type
(
args
[
0
]))
return
js_false
;
return
js_bool
(
util_has_proto_in_chain
(
js
,
args
[
0
],
g_map_iter_proto
));
}
static
ant_value_t
util_types_is_set_iterator
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
!
is_object_type
(
args
[
0
]))
return
js_false
;
return
js_bool
(
util_has_proto_in_chain
(
js
,
args
[
0
],
g_set_iter_proto
));
}
static
ant_value_t
util_types_is_module_namespace_object
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_false
;
return
js_bool
(
js_check_brand
(
args
[
0
],
BRAND_MODULE_NAMESPACE
));
}
ant_value_t
util_types_library
(
ant_t
*
js
)
{
ant_value_t
types
=
js_mkobj
(
js
);
js_set
(
js
,
types
,
"isAnyArrayBuffer"
,
js_mkfun
(
util_types_is_any_array_buffer
));
js_set
(
js
,
types
,
"isArrayBuffer"
,
js_mkfun
(
util_types_is_array_buffer
));
js_set
(
js
,
types
,
"isArgumentsObject"
,
js_mkfun
(
util_types_is_arguments_object
));
js_set
(
js
,
types
,
"isArrayBufferView"
,
js_mkfun
(
util_types_is_array_buffer_view
));
js_set
(
js
,
types
,
"isAsyncFunction"
,
js_mkfun
(
util_types_is_async_function
));
js_set
(
js
,
types
,
"isBigInt64Array"
,
js_mkfun
(
util_types_is_bigint64_array
));
js_set
(
js
,
types
,
"isBigIntObject"
,
js_mkfun
(
util_types_is_bigint_object
));
js_set
(
js
,
types
,
"isBigUint64Array"
,
js_mkfun
(
util_types_is_biguint64_array
));
js_set
(
js
,
types
,
"isBooleanObject"
,
js_mkfun
(
util_types_is_boolean_object
));
js_set
(
js
,
types
,
"isBoxedPrimitive"
,
js_mkfun
(
util_types_is_boxed_primitive
));
js_set
(
js
,
types
,
"isDataView"
,
js_mkfun
(
util_types_is_data_view
));
js_set
(
js
,
types
,
"isDate"
,
js_mkfun
(
util_types_is_date
));
js_set
(
js
,
types
,
"isFloat16Array"
,
js_mkfun
(
util_types_is_float16_array
));
js_set
(
js
,
types
,
"isFloat32Array"
,
js_mkfun
(
util_types_is_float32_array
));
js_set
(
js
,
types
,
"isFloat64Array"
,
js_mkfun
(
util_types_is_float64_array
));
js_set
(
js
,
types
,
"isGeneratorFunction"
,
js_mkfun
(
util_types_is_generator_function
));
js_set
(
js
,
types
,
"isGeneratorObject"
,
js_mkfun
(
util_types_is_generator_object
));
js_set
(
js
,
types
,
"isInt8Array"
,
js_mkfun
(
util_types_is_int8_array
));
js_set
(
js
,
types
,
"isInt16Array"
,
js_mkfun
(
util_types_is_int16_array
));
js_set
(
js
,
types
,
"isInt32Array"
,
js_mkfun
(
util_types_is_int32_array
));
js_set
(
js
,
types
,
"isMap"
,
js_mkfun
(
util_types_is_map
));
js_set
(
js
,
types
,
"isMapIterator"
,
js_mkfun
(
util_types_is_map_iterator
));
js_set
(
js
,
types
,
"isModuleNamespaceObject"
,
js_mkfun
(
util_types_is_module_namespace_object
));
js_set
(
js
,
types
,
"isNativeError"
,
js_mkfun
(
util_types_is_native_error
));
js_set
(
js
,
types
,
"isNumberObject"
,
js_mkfun
(
util_types_is_number_object
));
js_set
(
js
,
types
,
"isPromise"
,
js_mkfun
(
util_types_is_promise
));
js_set
(
js
,
types
,
"isProxy"
,
js_mkfun
(
util_types_is_proxy
));
js_set
(
js
,
types
,
"isRegExp"
,
js_mkfun
(
util_types_is_regexp
));
js_set
(
js
,
types
,
"isSet"
,
js_mkfun
(
util_types_is_set
));
js_set
(
js
,
types
,
"isSetIterator"
,
js_mkfun
(
util_types_is_set_iterator
));
js_set
(
js
,
types
,
"isSharedArrayBuffer"
,
js_mkfun
(
util_types_is_shared_array_buffer
));
js_set
(
js
,
types
,
"isStringObject"
,
js_mkfun
(
util_types_is_string_object
));
js_set
(
js
,
types
,
"isSymbolObject"
,
js_mkfun
(
util_types_is_symbol_object
));
js_set
(
js
,
types
,
"isTypedArray"
,
js_mkfun
(
util_types_is_typed_array
));
js_set
(
js
,
types
,
"isUint8Array"
,
js_mkfun
(
util_types_is_uint8_array
));
js_set
(
js
,
types
,
"isUint8ClampedArray"
,
js_mkfun
(
util_types_is_uint8_clamped_array
));
js_set
(
js
,
types
,
"isUint16Array"
,
js_mkfun
(
util_types_is_uint16_array
));
js_set
(
js
,
types
,
"isUint32Array"
,
js_mkfun
(
util_types_is_uint32_array
));
js_set
(
js
,
types
,
"isWeakMap"
,
js_mkfun
(
util_types_is_weak_map
));
js_set
(
js
,
types
,
"isWeakSet"
,
js_mkfun
(
util_types_is_weak_set
));
return
types
;
}
static
ant_value_t
util_get_types_object
(
ant_t
*
js
)
{
bool
loaded
=
false
;
ant_value_t
types
=
js_esm_load_registered_library
(
js
,
"util/types"
,
10
,
&
loaded
);
return
loaded
?
types
:
util_types_library
(
js
);
}
static
ant_value_t
util_debuglog_call
(
ant_params_t
)
{
return
js_mkundef
();
}
static
ant_value_t
util_debuglog
(
ant_params_t
)
{
ant_value_t
logger
=
js_mkfun
(
util_debuglog_call
);
js_set
(
js
,
logger
,
"enabled"
,
js_false
);
if
(
nargs
>=
2
&&
is_callable
(
args
[
1
]))
{
ant_value_t
cb_args
[
1
]
=
{
logger
};
ant_value_t
result
=
sv_vm_call
(
js
->
vm
,
js
,
args
[
1
],
js_mkundef
(),
cb_args
,
1
,
NULL
,
false
);
if
(
is_err
(
result
)
||
js
->
thrown_exists
)
return
result
;
}
return
logger
;
}
static
ant_value_t
util_strip_vt_control_characters
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkstr
(
js
,
""
,
0
);
char
cbuf
[
512
];
js_cstr_t
cstr
=
js_to_cstr
(
js
,
args
[
0
],
cbuf
,
sizeof
(
cbuf
));
const
char
*
src
=
cstr
.
ptr
;
size_t
len
=
strlen
(
src
);
util_sb_t
sb
=
{
0
};
for
(
size_t
i
=
0
;
i
<
len
;
i
++
)
{
unsigned
char
ch
=
(
unsigned
char
)
src
[
i
];
if
(
ch
!=
0x1b
)
{
util_sb_append_c
(
&
sb
,
(
char
)
ch
);
continue
;
}
if
(
i
+
1
<
len
&&
src
[
i
+
1
]
==
'['
)
{
i
+=
2
;
while
(
i
<
len
)
{
unsigned
char
c
=
(
unsigned
char
)
src
[
i
];
if
(
c
>=
'@'
&&
c
<=
'~'
)
break
;
i
++
;
}
continue
;
}
if
(
i
+
1
<
len
&&
src
[
i
+
1
]
==
']'
)
{
i
+=
2
;
while
(
i
<
len
)
{
if
((
unsigned
char
)
src
[
i
]
==
0x07
)
break
;
if
((
unsigned
char
)
src
[
i
]
==
0x1b
&&
i
+
1
<
len
&&
src
[
i
+
1
]
==
'\\'
)
{
i
++
;
break
;
}
i
++
;
}
continue
;
}
}
ant_value_t
out
=
js_mkstr
(
js
,
sb
.
buf
?
sb
.
buf
:
""
,
sb
.
len
);
if
(
cstr
.
needs_free
)
free
((
void
*
)
cstr
.
ptr
);
free
(
sb
.
buf
);
return
out
;
}
static
inline
bool
util_env_is_inline_ws
(
char
ch
)
{
return
ch
==
' '
||
ch
==
'\t'
||
ch
==
'\r'
;
}
static
inline
bool
util_env_is_ident_start
(
char
ch
)
{
return
(
ch
>=
'A'
&&
ch
<=
'Z'
)
||
(
ch
>=
'a'
&&
ch
<=
'z'
)
||
ch
==
'_'
;
}
static
inline
bool
util_env_is_ident_continue
(
char
ch
)
{
return
util_env_is_ident_start
(
ch
)
||
(
ch
>=
'0'
&&
ch
<=
'9'
);
}
static
void
util_env_skip_inline_ws
(
const
char
*
src
,
size_t
len
,
size_t
*
cursor
)
{
while
(
*
cursor
<
len
&&
util_env_is_inline_ws
(
src
[
*
cursor
]))
(
*
cursor
)
++
;
}
static
void
util_env_skip_line
(
const
char
*
src
,
size_t
len
,
size_t
*
cursor
)
{
while
(
*
cursor
<
len
&&
src
[
*
cursor
]
!=
'\n'
)
(
*
cursor
)
++
;
if
(
*
cursor
<
len
&&
src
[
*
cursor
]
==
'\n'
)
(
*
cursor
)
++
;
}
static
bool
util_env_consume_export
(
const
char
*
src
,
size_t
len
,
size_t
*
cursor
)
{
if
(
*
cursor
+
6
>
len
)
return
false
;
if
(
memcmp
(
src
+
*
cursor
,
"export"
,
6
)
!=
0
)
return
false
;
if
(
*
cursor
+
6
<
len
&&
!
util_env_is_inline_ws
(
src
[
*
cursor
+
6
])
&&
src
[
*
cursor
+
6
]
!=
'\n'
)
return
false
;
*
cursor
+=
6
;
util_env_skip_inline_ws
(
src
,
len
,
cursor
);
return
true
;
}
static
bool
util_env_parse_key
(
const
char
*
src
,
size_t
len
,
size_t
*
cursor
,
size_t
*
key_start
,
size_t
*
key_end
)
{
if
(
*
cursor
>=
len
||
!
util_env_is_ident_start
(
src
[
*
cursor
]))
return
false
;
*
key_start
=
*
cursor
;
(
*
cursor
)
++
;
while
(
*
cursor
<
len
&&
util_env_is_ident_continue
(
src
[
*
cursor
]))
(
*
cursor
)
++
;
*
key_end
=
*
cursor
;
return
true
;
}
static
void
util_env_set_entry
(
ant_t
*
js
,
ant_value_t
obj
,
const
char
*
key
,
size_t
key_len
,
ant_value_t
value
)
{
ant_value_t
key_str
=
js_mkstr
(
js
,
key
,
key_len
);
js_setprop
(
js
,
obj
,
key_str
,
value
);
}
static
ant_value_t
util_env_parse_quoted_value
(
ant_t
*
js
,
const
char
*
src
,
size_t
len
,
size_t
*
cursor
)
{
util_sb_t
sb
=
{
0
};
ant_value_t
value
=
js_mkstr
(
js
,
""
,
0
);
char
quote
;
if
(
*
cursor
>=
len
)
return
value
;
quote
=
src
[(
*
cursor
)
++
];
while
(
*
cursor
<
len
)
{
char
ch
=
src
[(
*
cursor
)
++
];
if
(
ch
==
quote
)
goto
done
;
if
(
ch
!=
'\\'
||
*
cursor
>=
len
)
{
util_sb_append_c
(
&
sb
,
ch
);
continue
;
}
char
esc
=
src
[(
*
cursor
)
++
];
if
(
quote
!=
'"'
)
{
util_sb_append_c
(
&
sb
,
esc
);
continue
;
}
switch
(
esc
)
{
case
'n'
:
util_sb_append_c
(
&
sb
,
'\n'
);
break
;
case
'r'
:
util_sb_append_c
(
&
sb
,
'\r'
);
break
;
case
't'
:
util_sb_append_c
(
&
sb
,
'\t'
);
break
;
case
'\\'
:
util_sb_append_c
(
&
sb
,
'\\'
);
break
;
case
'"'
:
util_sb_append_c
(
&
sb
,
'"'
);
break
;
default
:
util_sb_append_c
(
&
sb
,
esc
);
break
;
}
}
done
:
value
=
js_mkstr
(
js
,
sb
.
buf
?
sb
.
buf
:
""
,
sb
.
len
);
free
(
sb
.
buf
);
while
(
*
cursor
<
len
&&
src
[
*
cursor
]
!=
'\n'
)
{
if
(
src
[
*
cursor
]
==
'#'
)
break
;
(
*
cursor
)
++
;
}
return
value
;
}
static
ant_value_t
util_env_parse_unquoted_value
(
ant_t
*
js
,
const
char
*
src
,
size_t
len
,
size_t
*
cursor
)
{
size_t
value_start
=
*
cursor
;
size_t
value_end
=
*
cursor
;
bool
saw_space
=
false
;
while
(
*
cursor
<
len
&&
src
[
*
cursor
]
!=
'\n'
&&
src
[
*
cursor
]
!=
'\r'
)
{
if
(
src
[
*
cursor
]
==
'#'
)
{
if
(
*
cursor
==
value_start
||
saw_space
)
goto
done
;
}
saw_space
=
util_env_is_inline_ws
(
src
[
*
cursor
]);
(
*
cursor
)
++
;
value_end
=
*
cursor
;
}
done
:
while
(
value_start
<
value_end
&&
util_env_is_inline_ws
(
src
[
value_start
]))
{
value_start
++
;
}
while
(
value_end
>
value_start
&&
util_env_is_inline_ws
(
src
[
value_end
-
1
]))
{
value_end
--
;
}
return
js_mkstr
(
js
,
src
+
value_start
,
value_end
-
value_start
);
}
static
ant_value_t
util_parse_env
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
out
=
js_mkobj
(
js
);
if
(
nargs
<
1
)
return
out
;
char
cbuf
[
512
];
js_cstr_t
cstr
=
js_to_cstr
(
js
,
args
[
0
],
cbuf
,
sizeof
(
cbuf
));
const
char
*
src
=
cstr
.
ptr
;
size_t
len
=
strlen
(
src
);
size_t
i
=
0
;
if
(
len
>=
3
&&
(
unsigned
char
)
src
[
0
]
==
0xEF
&&
(
unsigned
char
)
src
[
1
]
==
0xBB
&&
(
unsigned
char
)
src
[
2
]
==
0xBF
)
{
i
=
3
;
}
while
(
i
<
len
)
{
size_t
key_start
=
0
;
size_t
key_end
=
0
;
ant_value_t
value
=
js_mkstr
(
js
,
""
,
0
);
util_env_skip_inline_ws
(
src
,
len
,
&
i
);
if
(
i
>=
len
)
break
;
if
(
src
[
i
]
==
'\n'
)
{
i
++
;
continue
;
}
if
(
src
[
i
]
==
'#'
)
goto
skip_line
;
util_env_consume_export
(
src
,
len
,
&
i
);
if
(
!
util_env_parse_key
(
src
,
len
,
&
i
,
&
key_start
,
&
key_end
))
goto
skip_line
;
util_env_skip_inline_ws
(
src
,
len
,
&
i
);
if
(
i
>=
len
||
src
[
i
]
!=
'='
)
goto
skip_line
;
i
++
;
util_env_skip_inline_ws
(
src
,
len
,
&
i
);
if
(
i
<
len
&&
(
src
[
i
]
==
'"'
||
src
[
i
]
==
'\''
||
src
[
i
]
==
'`'
))
{
value
=
util_env_parse_quoted_value
(
js
,
src
,
len
,
&
i
);
}
else
{
value
=
util_env_parse_unquoted_value
(
js
,
src
,
len
,
&
i
);
}
util_env_set_entry
(
js
,
out
,
src
+
key_start
,
key_end
-
key_start
,
value
);
skip_line
:
util_env_skip_line
(
src
,
len
,
&
i
);
}
if
(
cstr
.
needs_free
)
free
((
void
*
)
cstr
.
ptr
);
return
out
;
}
static
const
util_style_entry_t
*
util_find_style
(
const
char
*
name
)
{
for
(
size_t
i
=
0
;
i
<
sizeof
(
util_styles
)
/
sizeof
(
util_styles
[
0
]);
i
++
)
{
if
(
strcmp
(
name
,
util_styles
[
i
].
name
)
==
0
)
return
&
util_styles
[
i
];
}
return
NULL
;
}
static
ant_value_t
util_style_text
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkstr
(
js
,
""
,
0
);
char
text_buf
[
512
];
js_cstr_t
text_cstr
=
js_to_cstr
(
js
,
args
[
1
],
text_buf
,
sizeof
(
text_buf
));
const
util_style_entry_t
*
picked
[
16
];
int
picked_n
=
0
;
if
(
vtype
(
args
[
0
])
==
T_STR
)
{
const
char
*
name
=
js_getstr
(
js
,
args
[
0
],
NULL
);
const
util_style_entry_t
*
e
=
name
?
util_find_style
(
name
)
:
NULL
;
if
(
e
)
picked
[
picked_n
++
]
=
e
;
}
else
if
(
vtype
(
args
[
0
])
==
T_ARR
)
{
ant_offset_t
len
=
js_arr_len
(
js
,
args
[
0
]);
for
(
ant_offset_t
i
=
0
;
i
<
len
&&
picked_n
<
(
int
)(
sizeof
(
picked
)
/
sizeof
(
picked
[
0
]));
i
++
)
{
ant_value_t
item
=
js_arr_get
(
js
,
args
[
0
],
i
);
if
(
vtype
(
item
)
!=
T_STR
)
continue
;
const
char
*
name
=
js_getstr
(
js
,
item
,
NULL
);
const
util_style_entry_t
*
e
=
name
?
util_find_style
(
name
)
:
NULL
;
if
(
e
)
picked
[
picked_n
++
]
=
e
;
}
}
if
(
picked_n
==
0
)
{
ant_value_t
out
=
js_mkstr
(
js
,
text_cstr
.
ptr
,
strlen
(
text_cstr
.
ptr
));
if
(
text_cstr
.
needs_free
)
free
((
void
*
)
text_cstr
.
ptr
);
return
out
;
}
util_sb_t
sb
=
{
0
};
for
(
int
i
=
0
;
i
<
picked_n
;
i
++
)
{
util_sb_append_n
(
&
sb
,
picked
[
i
]
->
open
,
strlen
(
picked
[
i
]
->
open
));
}
util_sb_append_n
(
&
sb
,
text_cstr
.
ptr
,
strlen
(
text_cstr
.
ptr
));
for
(
int
i
=
picked_n
-
1
;
i
>=
0
;
i
--
)
{
util_sb_append_n
(
&
sb
,
picked
[
i
]
->
close
,
strlen
(
picked
[
i
]
->
close
));
}
ant_value_t
out
=
js_mkstr
(
js
,
sb
.
buf
?
sb
.
buf
:
""
,
sb
.
len
);
if
(
text_cstr
.
needs_free
)
free
((
void
*
)
text_cstr
.
ptr
);
free
(
sb
.
buf
);
return
out
;
}
static
ant_value_t
util_promisify_callback
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
fn
=
js_getcurrentfunc
(
js
);
ant_value_t
ctx
=
js_get_slot
(
fn
,
SLOT_DATA
);
if
(
!
is_object_type
(
ctx
))
return
js_mkundef
();
ant_value_t
settled
=
js_get_slot
(
ctx
,
SLOT_SETTLED
);
if
(
vtype
(
settled
)
==
T_BOOL
&&
settled
==
js_true
)
return
js_mkundef
();
js_set_slot
(
ctx
,
SLOT_SETTLED
,
js_true
);
ant_value_t
promise
=
js_get_slot
(
ctx
,
SLOT_DATA
);
if
(
!
is_object_type
(
promise
))
return
js_mkundef
();
if
(
nargs
>
0
&&
!
is_null
(
args
[
0
])
&&
!
is_undefined
(
args
[
0
]))
{
js_reject_promise
(
js
,
promise
,
args
[
0
]);
return
js_mkundef
();
}
if
(
nargs
<=
1
)
{
js_resolve_promise
(
js
,
promise
,
js_mkundef
());
return
js_mkundef
();
}
if
(
nargs
==
2
)
{
js_resolve_promise
(
js
,
promise
,
args
[
1
]);
return
js_mkundef
();
}
ant_value_t
arr
=
js_mkarr
(
js
);
for
(
int
i
=
1
;
i
<
nargs
;
i
++
)
js_arr_push
(
js
,
arr
,
args
[
i
]);
js_resolve_promise
(
js
,
promise
,
arr
);
return
js_mkundef
();
}
static
ant_value_t
util_promisified_call
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
fn
=
js_getcurrentfunc
(
js
);
ant_value_t
original
=
js_get_slot
(
fn
,
SLOT_DATA
);
if
(
!
is_callable
(
original
))
return
js_mkerr
(
js
,
"promisified target is not callable"
);
ant_value_t
promise
=
js_mkpromise
(
js
);
ant_value_t
ctx
=
js_mkobj
(
js
);
js_set_slot
(
ctx
,
SLOT_DATA
,
promise
);
js_set_slot
(
ctx
,
SLOT_SETTLED
,
js_false
);
ant_value_t
cb
=
js_heavy_mkfun
(
js
,
util_promisify_callback
,
ctx
);
ant_value_t
*
call_args
=
(
ant_value_t
*
)
malloc
((
size_t
)(
nargs
+
1
)
*
sizeof
(
ant_value_t
));
if
(
!
call_args
)
{
js_reject_promise
(
js
,
promise
,
js_mkerr
(
js
,
"Out of memory"
));
return
promise
;
}
for
(
int
i
=
0
;
i
<
nargs
;
i
++
)
call_args
[
i
]
=
args
[
i
];
call_args
[
nargs
]
=
cb
;
ant_value_t
this_arg
=
js_getthis
(
js
);
ant_value_t
call_result
=
sv_vm_call
(
js
->
vm
,
js
,
original
,
this_arg
,
call_args
,
nargs
+
1
,
NULL
,
false
);
free
(
call_args
);
ant_value_t
settled
=
js_get_slot
(
ctx
,
SLOT_SETTLED
);
bool
is_settled
=
(
vtype
(
settled
)
==
T_BOOL
&&
settled
==
js_true
);
if
(
!
is_settled
&&
(
is_err
(
call_result
)
||
js
->
thrown_exists
))
{
ant_value_t
ex
=
js
->
thrown_exists
?
js
->
thrown_value
:
call_result
;
js
->
thrown_exists
=
false
;
js
->
thrown_value
=
js_mkundef
();
js
->
thrown_stack
=
js_mkundef
();
js_set_slot
(
ctx
,
SLOT_SETTLED
,
js_true
);
js_reject_promise
(
js
,
promise
,
ex
);
}
return
promise
;
}
static
ant_value_t
util_callbackify_success
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
state
=
js_get_slot
(
js_getcurrentfunc
(
js
),
SLOT_DATA
);
if
(
!
is_object_type
(
state
))
return
js_mkundef
();
ant_value_t
callback
=
js_get_slot
(
state
,
SLOT_DATA
);
if
(
!
is_callable
(
callback
))
return
js_mkundef
();
ant_value_t
cb_args
[
2
]
=
{
js_mknull
(),
nargs
>
0
?
args
[
0
]
:
js_mkundef
()
};
return
sv_vm_call
(
js
->
vm
,
js
,
callback
,
js_mkundef
(),
cb_args
,
2
,
NULL
,
false
);
}
static
ant_value_t
util_callbackify_error
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
state
=
js_get_slot
(
js_getcurrentfunc
(
js
),
SLOT_DATA
);
if
(
!
is_object_type
(
state
))
return
js_mkundef
();
ant_value_t
callback
=
js_get_slot
(
state
,
SLOT_DATA
);
if
(
!
is_callable
(
callback
))
return
js_mkundef
();
ant_value_t
err
=
nargs
>
0
?
args
[
0
]
:
js_mkerr
(
js
,
"Promise was rejected"
);
ant_value_t
cb_args
[
1
]
=
{
err
};
return
sv_vm_call
(
js
->
vm
,
js
,
callback
,
js_mkundef
(),
cb_args
,
1
,
NULL
,
false
);
}
static
ant_value_t
util_callbackified_call
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
fn
=
js_getcurrentfunc
(
js
);
ant_value_t
original
=
js_get_slot
(
fn
,
SLOT_DATA
);
if
(
!
is_callable
(
original
))
return
js_mkerr
(
js
,
"callbackified target is not callable"
);
if
(
nargs
<
1
||
!
is_callable
(
args
[
nargs
-
1
]))
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"callbackified function requires a callback"
);
ant_value_t
callback
=
args
[
nargs
-
1
];
int
call_nargs
=
nargs
-
1
;
ant_value_t
*
call_args
=
NULL
;
if
(
call_nargs
>
0
)
{
call_args
=
(
ant_value_t
*
)
malloc
((
size_t
)
call_nargs
*
sizeof
(
ant_value_t
));
if
(
!
call_args
)
return
js_mkerr
(
js
,
"Out of memory"
);
for
(
int
i
=
0
;
i
<
call_nargs
;
i
++
)
call_args
[
i
]
=
args
[
i
];
}
ant_value_t
result
=
sv_vm_call
(
js
->
vm
,
js
,
original
,
js_getthis
(
js
),
call_args
,
call_nargs
,
NULL
,
false
);
free
(
call_args
);
if
(
is_err
(
result
)
||
js
->
thrown_exists
)
{
ant_value_t
ex
=
js
->
thrown_exists
?
js
->
thrown_value
:
result
;
js
->
thrown_exists
=
false
;
js
->
thrown_value
=
js_mkundef
();
js
->
thrown_stack
=
js_mkundef
();
ant_value_t
cb_args
[
1
]
=
{
ex
};
sv_vm_call
(
js
->
vm
,
js
,
callback
,
js_mkundef
(),
cb_args
,
1
,
NULL
,
false
);
return
js_mkundef
();
}
if
(
vtype
(
result
)
!=
T_PROMISE
)
{
ant_value_t
cb_args
[
2
]
=
{
js_mknull
(),
result
};
sv_vm_call
(
js
->
vm
,
js
,
callback
,
js_mkundef
(),
cb_args
,
2
,
NULL
,
false
);
return
js_mkundef
();
}
ant_value_t
state
=
js_mkobj
(
js
);
js_set_slot
(
state
,
SLOT_DATA
,
callback
);
ant_value_t
success
=
js_heavy_mkfun
(
js
,
util_callbackify_success
,
state
);
ant_value_t
error
=
js_heavy_mkfun
(
js
,
util_callbackify_error
,
state
);
js_promise_then
(
js
,
result
,
success
,
error
);
return
js_mkundef
();
}
static
ant_value_t
util_deprecated_call
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
fn
=
js_getcurrentfunc
(
js
);
ant_value_t
ctx
=
js_get_slot
(
fn
,
SLOT_DATA
);
if
(
!
is_object_type
(
ctx
))
return
js_mkundef
();
ant_value_t
warned
=
js_get_slot
(
ctx
,
SLOT_SETTLED
);
if
(
!
(
vtype
(
warned
)
==
T_BOOL
&&
warned
==
js_true
))
{
js_set_slot
(
ctx
,
SLOT_SETTLED
,
js_true
);
ant_value_t
msg_val
=
js_get
(
js
,
ctx
,
"msg"
);
const
char
*
msg
=
js_getstr
(
js
,
msg_val
,
NULL
);
if
(
msg
)
fprintf
(
stderr
,
"DeprecationWarning: %s
\n
"
,
msg
);
}
ant_value_t
original
=
js_get_slot
(
ctx
,
SLOT_DATA
);
ant_value_t
this_arg
=
js_getthis
(
js
);
return
sv_vm_call
(
js
->
vm
,
js
,
original
,
this_arg
,
args
,
nargs
,
NULL
,
false
);
}
static
ant_value_t
util_deprecate
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
!
is_callable
(
args
[
0
]))
{
return
js_mkerr
(
js
,
"deprecate(fn, msg) requires a function"
);
}
ant_value_t
ctx
=
js_mkobj
(
js
);
js_set_slot
(
ctx
,
SLOT_DATA
,
args
[
0
]);
js_set_slot
(
ctx
,
SLOT_SETTLED
,
js_false
);
if
(
nargs
>=
2
)
js_set
(
js
,
ctx
,
"msg"
,
args
[
1
]);
return
js_heavy_mkfun
(
js
,
util_deprecated_call
,
ctx
);
}
static
ant_value_t
util_promisify
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
!
is_callable
(
args
[
0
]))
{
return
js_mkerr
(
js
,
"promisify(fn) requires a function"
);
}
ant_value_t
custom
=
js_get_symbol
(
js
,
args
[
0
],
"nodejs.util.promisify.custom"
);
if
(
is_callable
(
custom
))
return
custom
;
return
js_heavy_mkfun
(
js
,
util_promisified_call
,
args
[
0
]);
}
static
ant_value_t
util_callbackify
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
!
is_callable
(
args
[
0
]))
{
return
js_mkerr
(
js
,
"callbackify(fn) requires a function"
);
}
return
js_heavy_mkfun
(
js
,
util_callbackified_call
,
args
[
0
]);
}
static
ant_value_t
util_aborted_listener
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
promise
=
js_get_slot
(
js_getcurrentfunc
(
js
),
SLOT_DATA
);
if
(
vtype
(
promise
)
==
T_PROMISE
)
js_resolve_promise
(
js
,
promise
,
js_mkundef
());
return
js_mkundef
();
}
static
ant_value_t
util_aborted
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
!
abort_signal_is_signal
(
args
[
0
]))
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"aborted(signal, resource) requires an AbortSignal"
);
ant_value_t
promise
=
js_mkpromise
(
js
);
if
(
abort_signal_is_aborted
(
args
[
0
]))
{
js_resolve_promise
(
js
,
promise
,
js_mkundef
());
return
promise
;
}
abort_signal_add_listener
(
js
,
args
[
0
],
js_heavy_mkfun
(
js
,
util_aborted_listener
,
promise
));
return
promise
;
}
static
ant_value_t
util_inherits
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
||
!
is_callable
(
args
[
0
])
||
!
is_callable
(
args
[
1
]))
{
return
js_mkerr
(
js
,
"inherits(ctor, superCtor) requires constructor functions"
);
}
ant_value_t
ctor
=
args
[
0
];
ant_value_t
super_ctor
=
args
[
1
];
ant_value_t
ctor_proto
=
js_get
(
js
,
ctor
,
"prototype"
);
ant_value_t
super_proto
=
js_get
(
js
,
super_ctor
,
"prototype"
);
if
(
!
is_object_type
(
ctor_proto
)
||
!
is_object_type
(
super_proto
))
{
return
js_mkerr
(
js
,
"inherits(ctor, superCtor) requires prototype objects"
);
}
js_set
(
js
,
ctor
,
"super_"
,
super_ctor
);
js_set_proto_init
(
ctor_proto
,
super_proto
);
return
js_mkundef
();
}
static
ant_value_t
util_is_deep_strict_equal
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_bool
(
true
);
return
js_bool
(
js_deep_equal
(
js
,
args
[
0
],
args
[
1
],
true
));
}
ant_value_t
util_library
(
ant_t
*
js
)
{
ant_value_t
lib
=
js_mkobj
(
js
);
ant_value_t
types
=
util_get_types_object
(
js
);
ant_value_t
promisify
=
js_heavy_mkfun
(
js
,
util_promisify
,
js_mkundef
());
js_set
(
js
,
promisify
,
"custom"
,
js_mksym_for
(
js
,
"nodejs.util.promisify.custom"
));
js_set
(
js
,
lib
,
"format"
,
js_mkfun
(
util_format
));
js_set
(
js
,
lib
,
"formatWithOptions"
,
js_mkfun
(
util_format_with_options
));
js_set
(
js
,
lib
,
"debuglog"
,
js_mkfun
(
util_debuglog
));
js_set
(
js
,
lib
,
"inspect"
,
js_mkfun
(
util_inspect
));
js_set
(
js
,
lib
,
"deprecate"
,
js_mkfun
(
util_deprecate
));
js_set
(
js
,
lib
,
"inherits"
,
js_mkfun
(
util_inherits
));
js_set
(
js
,
lib
,
"isDeepStrictEqual"
,
js_mkfun
(
util_is_deep_strict_equal
));
js_set
(
js
,
lib
,
"parseArgs"
,
js_mkfun
(
util_parse_args
));
js_set
(
js
,
lib
,
"parseEnv"
,
js_mkfun
(
util_parse_env
));
js_set
(
js
,
lib
,
"promisify"
,
promisify
);
js_set
(
js
,
lib
,
"callbackify"
,
js_mkfun
(
util_callbackify
));
js_set
(
js
,
lib
,
"aborted"
,
js_mkfun
(
util_aborted
));
js_set
(
js
,
lib
,
"stripVTControlCharacters"
,
js_mkfun
(
util_strip_vt_control_characters
));
js_set
(
js
,
lib
,
"styleText"
,
js_mkfun
(
util_style_text
));
js_set
(
js
,
lib
,
"types"
,
types
);
js_set_sym
(
js
,
lib
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"util"
,
4
));
return
lib
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sat, May 2, 8:14 AM (2 d)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
541653
Default Alt Text
util.c (45 KB)
Attached To
Mode
rANT Ant
Attached
Detach File
Event Timeline
Log In to Comment