Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F4497601
util.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
util.c
View Options
#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
"silver/engine.h"
#include
"modules/json.h"
#include
"modules/symbol.h"
#include
"modules/util.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
;
// 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
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
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
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_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"
);
}
return
js_heavy_mkfun
(
js
,
util_promisified_call
,
args
[
0
]);
}
ant_value_t
util_library
(
ant_t
*
js
)
{
ant_value_t
lib
=
js_mkobj
(
js
);
js_set
(
js
,
lib
,
"format"
,
js_mkfun
(
util_format
));
js_set
(
js
,
lib
,
"formatWithOptions"
,
js_mkfun
(
util_format_with_options
));
js_set
(
js
,
lib
,
"inspect"
,
js_mkfun
(
util_inspect
));
js_set
(
js
,
lib
,
"deprecate"
,
js_mkfun
(
util_deprecate
));
js_set
(
js
,
lib
,
"promisify"
,
js_mkfun
(
util_promisify
));
js_set
(
js
,
lib
,
"stripVTControlCharacters"
,
js_mkfun
(
util_strip_vt_control_characters
));
js_set
(
js
,
lib
,
"styleText"
,
js_mkfun
(
util_style_text
));
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
Sun, May 3, 7:19 AM (2 h, 37 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
538252
Default Alt Text
util.c (13 KB)
Attached To
Mode
rANT Ant
Attached
Detach File
Event Timeline
Log In to Comment