Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F4432096
process.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
61 KB
Referenced Files
None
Subscribers
None
process.c
View Options
#include
<compat.h>
// IWYU pragma: keep
#include
<stdlib.h>
#include
<stdio.h>
#include
<string.h>
#include
<signal.h>
#include
<time.h>
#include
<uthash.h>
#include
<uv.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include
<windows.h>
#include
<io.h>
#include
<psapi.h>
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
#else
#include
<termios.h>
#include
<unistd.h>
#include
<sys/ioctl.h>
#include
<sys/time.h>
#include
<sys/resource.h>
#include
<sys/stat.h>
#include
<grp.h>
#include
<pwd.h>
#endif
#include
"ant.h"
#include
"errors.h"
#include
"output.h"
#include
"utils.h"
#include
"tty_ctrl.h"
#include
"internal.h"
#include
"descriptors.h"
#include
"runtime.h"
#include
"silver/engine.h"
#include
"gc/modules.h"
#include
"modules/process.h"
#include
"modules/tty.h"
#include
"modules/symbol.h"
#include
"modules/buffer.h"
#include
"modules/napi.h"
#include
"modules/timer.h"
#include
"modules/string_decoder.h"
#ifndef _WIN32
extern
char
**
environ
;
#else
#define environ _environ
#endif
#define DEFAULT_MAX_LISTENERS 10
#define INITIAL_LISTENER_CAPACITY 4
typedef
struct
{
ant_value_t
listener
;
bool
once
;
}
ProcessEventListener
;
typedef
struct
{
char
*
event_type
;
ProcessEventListener
*
listeners
;
int
listener_count
;
int
listener_capacity
;
int
emitting
;
bool
free_deferred
;
UT_hash_handle
hh
;
}
ProcessEventType
;
static
int
max_listeners
=
DEFAULT_MAX_LISTENERS
;
static
ProcessEventType
*
process_events
=
NULL
;
typedef
struct
{
uv_signal_t
handle
;
int
signum
;
UT_hash_handle
hh
;
}
SignalHandle
;
static
SignalHandle
*
signal_handles
=
NULL
;
static
ProcessEventType
*
stdin_events
=
NULL
;
static
ProcessEventType
*
stdout_events
=
NULL
;
static
ProcessEventType
*
stderr_events
=
NULL
;
typedef
struct
{
uv_tty_t
tty
;
bool
tty_initialized
;
bool
reading
;
bool
keypress_enabled
;
ant_value_t
decoder
;
int
escape_state
;
int
escape_len
;
char
escape_buf
[
16
];
}
stdin_state_t
;
static
stdin_state_t
stdin_state
=
{
0
};
static
uint64_t
process_start_time
=
0
;
#ifndef _WIN32
static
uv_signal_t
sigwinch_handle
;
static
bool
sigwinch_initialized
=
false
;
#endif
typedef
struct
{
const
char
*
name
;
int
signum
;
UT_hash_handle
hh_name
;
UT_hash_handle
hh_num
;
}
SignalEntry
;
static
SignalEntry
*
signals_by_name
=
NULL
;
static
SignalEntry
*
signals_by_num
=
NULL
;
static
void
init_signal_map
(
void
)
{
static
bool
initialized
=
false
;
if
(
initialized
)
return
;
#define S(sig) { #sig, sig, {0}, {0} }
static
SignalEntry
entries
[]
=
{
S
(
SIGINT
),
S
(
SIGILL
),
S
(
SIGABRT
),
S
(
SIGFPE
),
S
(
SIGSEGV
),
S
(
SIGTERM
),
#ifdef SIGHUP
S
(
SIGHUP
),
#endif
#ifdef SIGQUIT
S
(
SIGQUIT
),
#endif
#ifdef SIGTRAP
S
(
SIGTRAP
),
#endif
#ifdef SIGKILL
S
(
SIGKILL
),
#endif
#ifdef SIGBUS
S
(
SIGBUS
),
#endif
#ifdef SIGSYS
S
(
SIGSYS
),
#endif
#ifdef SIGPIPE
S
(
SIGPIPE
),
#endif
#ifdef SIGALRM
S
(
SIGALRM
),
#endif
#ifdef SIGURG
S
(
SIGURG
),
#endif
#ifdef SIGSTOP
S
(
SIGSTOP
),
#endif
#ifdef SIGTSTP
S
(
SIGTSTP
),
#endif
#ifdef SIGCONT
S
(
SIGCONT
),
#endif
#ifdef SIGCHLD
S
(
SIGCHLD
),
#endif
#ifdef SIGTTIN
S
(
SIGTTIN
),
#endif
#ifdef SIGTTOU
S
(
SIGTTOU
),
#endif
#ifdef SIGXCPU
S
(
SIGXCPU
),
#endif
#ifdef SIGXFSZ
S
(
SIGXFSZ
),
#endif
#ifdef SIGVTALRM
S
(
SIGVTALRM
),
#endif
#ifdef SIGPROF
S
(
SIGPROF
),
#endif
#ifdef SIGUSR1
S
(
SIGUSR1
),
#endif
#ifdef SIGUSR2
S
(
SIGUSR2
),
#endif
#ifdef SIGEMT
S
(
SIGEMT
),
#endif
#ifdef SIGIO
S
(
SIGIO
),
#endif
#ifdef SIGWINCH
S
(
SIGWINCH
),
#endif
#ifdef SIGINFO
S
(
SIGINFO
),
#endif
#ifdef SIGPWR
S
(
SIGPWR
),
#endif
#ifdef SIGSTKFLT
S
(
SIGSTKFLT
),
#endif
#ifdef SIGPOLL
S
(
SIGPOLL
),
#endif
};
#undef S
size_t
count
=
sizeof
(
entries
)
/
sizeof
(
entries
[
0
]);
for
(
size_t
i
=
0
;
i
<
count
;
i
++
)
{
HASH_ADD_KEYPTR
(
hh_name
,
signals_by_name
,
entries
[
i
].
name
,
strlen
(
entries
[
i
].
name
),
&
entries
[
i
]);
HASH_ADD
(
hh_num
,
signals_by_num
,
signum
,
sizeof
(
int
),
&
entries
[
i
]);
}
initialized
=
true
;
}
static
int
get_signal_number
(
const
char
*
name
)
{
init_signal_map
();
SignalEntry
*
entry
=
NULL
;
HASH_FIND
(
hh_name
,
signals_by_name
,
name
,
strlen
(
name
),
entry
);
return
entry
?
entry
->
signum
:
-1
;
}
static
const
char
*
get_signal_name
(
int
signum
)
{
init_signal_map
();
SignalEntry
*
entry
=
NULL
;
HASH_FIND
(
hh_num
,
signals_by_num
,
&
signum
,
sizeof
(
int
),
entry
);
return
entry
?
entry
->
name
:
NULL
;
}
static
ProcessEventType
*
find_or_create_event
(
ProcessEventType
**
table
,
const
char
*
event_type
)
{
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
*
table
,
event_type
,
evt
);
if
(
evt
==
NULL
)
{
evt
=
malloc
(
sizeof
(
ProcessEventType
));
*
evt
=
(
ProcessEventType
){
.
event_type
=
strdup
(
event_type
),
.
emitting
=
0
,
.
listener_count
=
0
,
.
free_deferred
=
false
,
.
listener_capacity
=
INITIAL_LISTENER_CAPACITY
,
.
listeners
=
malloc
(
sizeof
(
ProcessEventListener
)
*
INITIAL_LISTENER_CAPACITY
),
};
HASH_ADD_KEYPTR
(
hh
,
*
table
,
evt
->
event_type
,
strlen
(
evt
->
event_type
),
evt
);
}
return
evt
;
}
static
bool
ensure_listener_capacity
(
ProcessEventType
*
evt
)
{
if
(
evt
->
listener_count
>=
evt
->
listener_capacity
)
{
int
new_capacity
=
evt
->
listener_capacity
*
2
;
ProcessEventListener
*
new_listeners
=
realloc
(
evt
->
listeners
,
sizeof
(
ProcessEventListener
)
*
new_capacity
);
if
(
!
new_listeners
)
return
false
;
evt
->
listeners
=
new_listeners
;
evt
->
listener_capacity
=
new_capacity
;
}
return
true
;
}
static
void
free_event_type
(
ProcessEventType
**
events
,
ProcessEventType
*
evt
)
{
if
(
!
evt
)
return
;
if
(
evt
->
emitting
>
0
)
{
evt
->
free_deferred
=
true
;
return
;
}
HASH_DEL
(
*
events
,
evt
);
free
(
evt
->
listeners
);
free
(
evt
->
event_type
);
free
(
evt
);
}
static
void
check_listener_warning
(
const
char
*
event
)
{
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
process_events
,
event
,
evt
);
if
(
evt
&&
evt
->
listener_count
==
max_listeners
)
fprintf
(
stderr
,
"Warning: Possible EventEmitter memory leak detected. "
"%d '%s' listeners added. Use process.setMaxListeners() to increase limit.
\n
"
,
evt
->
listener_count
,
event
);
}
static
void
uv_signal_handler
(
uv_signal_t
*
handle
,
int
signum
)
{
const
char
*
name
=
get_signal_name
(
signum
);
if
(
name
)
{
ant_value_t
sig_arg
=
js_mkstr
(
rt
->
js
,
name
,
strlen
(
name
));
emit_process_event
(
name
,
&
sig_arg
,
1
);
}
}
static
void
start_signal_watch
(
int
signum
)
{
SignalHandle
*
sh
=
NULL
;
HASH_FIND_INT
(
signal_handles
,
&
signum
,
sh
);
if
(
sh
)
return
;
sh
=
malloc
(
sizeof
(
SignalHandle
));
sh
->
signum
=
signum
;
uv_signal_init
(
uv_default_loop
(),
&
sh
->
handle
);
uv_signal_start
(
&
sh
->
handle
,
uv_signal_handler
,
signum
);
uv_unref
((
uv_handle_t
*
)
&
sh
->
handle
);
HASH_ADD_INT
(
signal_handles
,
signum
,
sh
);
}
static
void
on_signal_handle_close
(
uv_handle_t
*
handle
)
{
SignalHandle
*
sh
=
(
SignalHandle
*
)
handle
;
free
(
sh
);
}
static
void
stop_signal_watch
(
int
signum
)
{
SignalHandle
*
sh
=
NULL
;
HASH_FIND_INT
(
signal_handles
,
&
signum
,
sh
);
if
(
!
sh
)
return
;
HASH_DEL
(
signal_handles
,
sh
);
uv_signal_stop
(
&
sh
->
handle
);
uv_close
((
uv_handle_t
*
)
&
sh
->
handle
,
on_signal_handle_close
);
}
void
emit_process_event
(
const
char
*
event_type
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
!
rt
->
js
)
return
;
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
process_events
,
event_type
,
evt
);
if
(
evt
==
NULL
||
evt
->
listener_count
==
0
)
return
;
evt
->
emitting
++
;
int
i
=
0
;
while
(
i
<
evt
->
listener_count
)
{
ProcessEventListener
*
listener
=
&
evt
->
listeners
[
i
];
sv_vm_call
(
rt
->
js
->
vm
,
rt
->
js
,
listener
->
listener
,
js_mkundef
(),
args
,
nargs
,
NULL
,
false
);
if
(
listener
->
once
)
{
for
(
int
j
=
i
;
j
<
evt
->
listener_count
-
1
;
j
++
)
{
evt
->
listeners
[
j
]
=
evt
->
listeners
[
j
+
1
];
}
evt
->
listener_count
--
;
}
else
i
++
;
}
evt
->
emitting
--
;
if
(
evt
->
listener_count
==
0
||
evt
->
free_deferred
)
{
int
signum
=
get_signal_number
(
event_type
);
if
(
signum
>
0
)
stop_signal_watch
(
signum
);
if
(
evt
->
emitting
==
0
)
free_event_type
(
&
process_events
,
evt
);
}
}
bool
process_has_event_listeners
(
const
char
*
event_type
)
{
ProcessEventType
*
evt
=
NULL
;
if
(
!
event_type
)
return
false
;
HASH_FIND_STR
(
process_events
,
event_type
,
evt
);
return
evt
&&
evt
->
listener_count
>
0
;
}
static
void
emit_stdio_event
(
ProcessEventType
**
events
,
const
char
*
event_type
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
!
rt
->
js
)
return
;
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
*
events
,
event_type
,
evt
);
if
(
evt
==
NULL
||
evt
->
listener_count
==
0
)
return
;
evt
->
emitting
++
;
int
i
=
0
;
while
(
i
<
evt
->
listener_count
)
{
ProcessEventListener
*
listener
=
&
evt
->
listeners
[
i
];
sv_vm_call
(
rt
->
js
->
vm
,
rt
->
js
,
listener
->
listener
,
js_mkundef
(),
args
,
nargs
,
NULL
,
false
);
if
(
listener
->
once
)
{
for
(
int
j
=
i
;
j
<
evt
->
listener_count
-
1
;
j
++
)
evt
->
listeners
[
j
]
=
evt
->
listeners
[
j
+
1
];
evt
->
listener_count
--
;
}
else
i
++
;
}
evt
->
emitting
--
;
if
((
evt
->
listener_count
==
0
||
evt
->
free_deferred
)
&&
evt
->
emitting
==
0
)
free_event_type
(
events
,
evt
);
}
static
const
char
*
stdin_escape_name
(
const
char
*
seq
,
int
len
)
{
if
(
len
<
2
)
return
NULL
;
if
(
seq
[
0
]
==
'['
)
{
if
(
seq
[
1
]
>=
'0'
&&
seq
[
1
]
<=
'9'
)
{
int
num
=
0
;
int
idx
=
1
;
while
(
idx
<
len
&&
seq
[
idx
]
>=
'0'
&&
seq
[
idx
]
<=
'9'
)
{
num
=
num
*
10
+
(
seq
[
idx
]
-
'0'
);
idx
++
;
}
if
(
idx
<
len
&&
seq
[
idx
]
==
'~'
)
{
typedef
struct
{
int
code
;
const
char
*
name
;
}
esc_num_map_t
;
static
const
esc_num_map_t
esc_num_map
[]
=
{
{
1
,
"home"
},
{
2
,
"insert"
},
{
3
,
"delete"
},
{
4
,
"end"
},
{
5
,
"pageup"
},
{
6
,
"pagedown"
},
{
7
,
"home"
},
{
8
,
"end"
},
{
15
,
"f5"
},
{
17
,
"f6"
},
{
18
,
"f7"
},
{
19
,
"f8"
},
{
20
,
"f9"
},
{
21
,
"f10"
},
{
23
,
"f11"
},
{
24
,
"f12"
},
};
for
(
size_t
i
=
0
;
i
<
sizeof
(
esc_num_map
)
/
sizeof
(
esc_num_map
[
0
]);
i
++
)
{
if
(
esc_num_map
[
i
].
code
==
num
)
return
esc_num_map
[
i
].
name
;
}
}
return
NULL
;
}
typedef
struct
{
char
code
;
bool
needs_tilde
;
const
char
*
name
;
}
esc_map_t
;
static
const
esc_map_t
esc_map
[]
=
{
{
'A'
,
false
,
"up"
},
{
'B'
,
false
,
"down"
},
{
'C'
,
false
,
"right"
},
{
'D'
,
false
,
"left"
},
{
'H'
,
false
,
"home"
},
{
'F'
,
false
,
"end"
},
{
'Z'
,
false
,
"tab"
},
{
'2'
,
true
,
"insert"
},
{
'3'
,
true
,
"delete"
},
{
'5'
,
true
,
"pageup"
},
{
'6'
,
true
,
"pagedown"
},
};
for
(
size_t
i
=
0
;
i
<
sizeof
(
esc_map
)
/
sizeof
(
esc_map
[
0
]);
i
++
)
{
if
(
seq
[
1
]
!=
esc_map
[
i
].
code
)
continue
;
if
(
esc_map
[
i
].
needs_tilde
)
{
return
(
len
>=
3
&&
seq
[
2
]
==
'~'
)
?
esc_map
[
i
].
name
:
NULL
;
}
return
esc_map
[
i
].
name
;
}
return
NULL
;
}
if
(
seq
[
0
]
==
'O'
)
{
switch
(
seq
[
1
])
{
case
'P'
:
return
"f1"
;
case
'Q'
:
return
"f2"
;
case
'R'
:
return
"f3"
;
case
'S'
:
return
"f4"
;
default
:
return
NULL
;
}
}
return
NULL
;
}
static
void
emit_keypress_event
(
ant_t
*
js
,
const
char
*
str
,
size_t
str_len
,
const
char
*
name
,
bool
ctrl
,
bool
meta
,
bool
shift
,
const
char
*
sequence
,
size_t
sequence_len
)
{
ant_value_t
str_val
=
js_mkstr
(
js
,
str
?
str
:
""
,
str
?
str_len
:
0
);
ant_value_t
key_obj
=
js_mkobj
(
js
);
if
(
name
)
{
js_set
(
js
,
key_obj
,
"name"
,
js_mkstr
(
js
,
name
,
strlen
(
name
)));
}
else
{
js_set
(
js
,
key_obj
,
"name"
,
js_mkundef
());
}
js_set
(
js
,
key_obj
,
"ctrl"
,
js_bool
(
ctrl
));
js_set
(
js
,
key_obj
,
"meta"
,
js_bool
(
meta
));
js_set
(
js
,
key_obj
,
"shift"
,
js_bool
(
shift
));
if
(
sequence
)
{
js_set
(
js
,
key_obj
,
"sequence"
,
js_mkstr
(
js
,
sequence
,
sequence_len
));
}
ant_value_t
args
[
2
]
=
{
str_val
,
key_obj
};
emit_stdio_event
(
&
stdin_events
,
"keypress"
,
args
,
2
);
}
static
void
process_keypress_data
(
ant_t
*
js
,
const
char
*
data
,
size_t
len
)
{
for
(
size_t
i
=
0
;
i
<
len
;
i
++
)
{
unsigned
char
c
=
(
unsigned
char
)
data
[
i
];
if
(
stdin_state
.
escape_state
==
1
)
{
stdin_state
.
escape_buf
[
stdin_state
.
escape_len
++
]
=
(
char
)
c
;
if
(
c
==
'['
||
c
==
'O'
)
{
stdin_state
.
escape_state
=
2
;
continue
;
}
emit_keypress_event
(
js
,
"
\x1b
"
,
1
,
"escape"
,
false
,
false
,
false
,
"
\x1b
"
,
1
);
stdin_state
.
escape_state
=
0
;
stdin_state
.
escape_len
=
0
;
}
if
(
stdin_state
.
escape_state
==
2
)
{
stdin_state
.
escape_buf
[
stdin_state
.
escape_len
++
]
=
(
char
)
c
;
if
((
c
>=
'A'
&&
c
<=
'Z'
)
||
c
==
'~'
||
stdin_state
.
escape_len
>=
15
)
{
char
sequence
[
18
];
size_t
seq_len
=
0
;
sequence
[
seq_len
++
]
=
'\x1b'
;
memcpy
(
sequence
+
seq_len
,
stdin_state
.
escape_buf
,
(
size_t
)
stdin_state
.
escape_len
);
seq_len
+=
(
size_t
)
stdin_state
.
escape_len
;
const
char
*
name
=
stdin_escape_name
(
stdin_state
.
escape_buf
,
stdin_state
.
escape_len
);
if
(
!
name
)
name
=
"escape"
;
emit_keypress_event
(
js
,
""
,
0
,
name
,
false
,
false
,
false
,
sequence
,
seq_len
);
stdin_state
.
escape_state
=
0
;
stdin_state
.
escape_len
=
0
;
}
continue
;
}
if
(
c
==
27
)
{
stdin_state
.
escape_state
=
1
;
stdin_state
.
escape_len
=
0
;
continue
;
}
if
(
c
==
'\r'
||
c
==
'\n'
)
{
emit_keypress_event
(
js
,
"
\r
"
,
1
,
"return"
,
false
,
false
,
false
,
"
\r
"
,
1
);
continue
;
}
if
(
c
==
127
||
c
==
8
)
{
emit_keypress_event
(
js
,
""
,
0
,
"backspace"
,
false
,
false
,
false
,
NULL
,
0
);
continue
;
}
if
(
c
==
'\t'
)
{
emit_keypress_event
(
js
,
"
\t
"
,
1
,
"tab"
,
false
,
false
,
false
,
"
\t
"
,
1
);
continue
;
}
if
(
c
<
32
)
{
char
name_buf
[
2
]
=
{
(
char
)(
'a'
+
c
-
1
),
'\0'
};
char
seq
=
(
char
)
c
;
emit_keypress_event
(
js
,
&
seq
,
1
,
name_buf
,
true
,
false
,
false
,
&
seq
,
1
);
continue
;
}
char
ch
=
(
char
)
c
;
char
name_buf
[
2
]
=
{
ch
,
'\0'
};
emit_keypress_event
(
js
,
&
ch
,
1
,
name_buf
,
false
,
false
,
false
,
&
ch
,
1
);
}
if
(
stdin_state
.
escape_state
==
1
)
{
emit_keypress_event
(
js
,
"
\x1b
"
,
1
,
"escape"
,
false
,
false
,
false
,
"
\x1b
"
,
1
);
stdin_state
.
escape_state
=
0
;
stdin_state
.
escape_len
=
0
;
}
}
static
bool
remove_listener_from_events
(
ProcessEventType
**
events
,
const
char
*
event
,
ant_value_t
listener
)
{
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
*
events
,
event
,
evt
);
if
(
!
evt
)
return
false
;
for
(
int
i
=
0
;
i
<
evt
->
listener_count
;
i
++
)
{
if
(
evt
->
listeners
[
i
].
listener
!=
listener
)
continue
;
memmove
(
&
evt
->
listeners
[
i
],
&
evt
->
listeners
[
i
+
1
],
(
size_t
)(
evt
->
listener_count
-
i
-
1
)
*
sizeof
(
ProcessEventListener
)
);
if
(
--
evt
->
listener_count
==
0
)
{
free_event_type
(
events
,
evt
);
return
true
;
}
return
false
;
}
return
false
;
}
static
bool
stdin_is_tty
(
void
)
{
return
uv_guess_handle
(
STDIN_FILENO
)
==
UV_TTY
;
}
static
bool
stdout_is_tty
(
void
)
{
return
uv_guess_handle
(
STDOUT_FILENO
)
==
UV_TTY
;
}
static
bool
stderr_is_tty
(
void
)
{
return
uv_guess_handle
(
STDERR_FILENO
)
==
UV_TTY
;
}
static
void
get_tty_size
(
int
fd
,
int
*
rows
,
int
*
cols
)
{
int
out_rows
=
24
,
out_cols
=
80
;
#ifndef _WIN32
struct
winsize
ws
;
if
(
ioctl
(
fd
,
TIOCGWINSZ
,
&
ws
)
==
0
)
{
if
(
ws
.
ws_row
>
0
)
out_rows
=
ws
.
ws_row
;
if
(
ws
.
ws_col
>
0
)
out_cols
=
ws
.
ws_col
;
}
#else
CONSOLE_SCREEN_BUFFER_INFO
csbi
;
if
(
GetConsoleScreenBufferInfo
(
GetStdHandle
(
STD_OUTPUT_HANDLE
),
&
csbi
))
{
int
width
=
csbi
.
srWindow
.
Right
-
csbi
.
srWindow
.
Left
+
1
;
int
height
=
csbi
.
srWindow
.
Bottom
-
csbi
.
srWindow
.
Top
+
1
;
if
(
height
>
0
)
out_rows
=
height
;
if
(
width
>
0
)
out_cols
=
width
;
}
#endif
if
(
rows
)
*
rows
=
out_rows
;
if
(
cols
)
*
cols
=
out_cols
;
}
static
bool
stdin_set_raw_mode
(
bool
enable
)
{
if
(
!
stdin_is_tty
())
return
false
;
return
tty_set_raw_mode
(
STDIN_FILENO
,
enable
);
}
static
void
stdin_alloc_buffer
(
uv_handle_t
*
handle
,
size_t
suggested_size
,
uv_buf_t
*
buf
)
{
(
void
)
handle
;
buf
->
base
=
malloc
(
suggested_size
);
#ifdef _WIN32
buf
->
len
=
(
ULONG
)
suggested_size
;
#else
buf
->
len
=
suggested_size
;
#endif
}
static
void
on_stdin_read
(
uv_stream_t
*
stream
,
ssize_t
nread
,
const
uv_buf_t
*
buf
)
{
(
void
)
stream
;
if
(
nread
>
0
&&
rt
->
js
)
{
ArrayBufferData
*
ab
=
create_array_buffer_data
((
size_t
)
nread
);
if
(
ab
)
memcpy
(
ab
->
data
,
buf
->
base
,
(
size_t
)
nread
);
ant_value_t
raw_val
=
ab
?
create_typed_array
(
rt
->
js
,
TYPED_ARRAY_UINT8
,
ab
,
0
,
(
size_t
)
nread
,
"Buffer"
)
:
js_mkstr
(
rt
->
js
,
buf
->
base
,
(
size_t
)
nread
);
ant_value_t
data_val
=
is_object_type
(
stdin_state
.
decoder
)
?
string_decoder_decode_value
(
rt
->
js
,
stdin_state
.
decoder
,
raw_val
,
false
)
:
raw_val
;
if
(
is_err
(
data_val
))
data_val
=
raw_val
;
emit_stdio_event
(
&
stdin_events
,
"data"
,
&
data_val
,
1
);
if
(
stdin_state
.
keypress_enabled
)
process_keypress_data
(
rt
->
js
,
buf
->
base
,
(
size_t
)
nread
);
}
if
(
buf
->
base
)
free
(
buf
->
base
);
}
static
void
stdin_start_reading
(
void
)
{
if
(
stdin_state
.
reading
)
return
;
if
(
!
stdin_state
.
tty_initialized
)
{
uv_loop_t
*
loop
=
uv_default_loop
();
if
(
uv_tty_init
(
loop
,
&
stdin_state
.
tty
,
STDIN_FILENO
,
1
)
!=
0
)
return
;
stdin_state
.
tty
.
data
=
NULL
;
stdin_state
.
tty_initialized
=
true
;
uv_unref
((
uv_handle_t
*
)
&
stdin_state
.
tty
);
}
uv_ref
((
uv_handle_t
*
)
&
stdin_state
.
tty
);
stdin_state
.
reading
=
true
;
uv_read_start
((
uv_stream_t
*
)
&
stdin_state
.
tty
,
stdin_alloc_buffer
,
on_stdin_read
);
}
static
void
stdin_stop_reading
(
void
)
{
if
(
!
stdin_state
.
reading
)
return
;
uv_read_stop
((
uv_stream_t
*
)
&
stdin_state
.
tty
);
stdin_state
.
reading
=
false
;
uv_unref
((
uv_handle_t
*
)
&
stdin_state
.
tty
);
}
#ifndef _WIN32
static
void
on_sigwinch
(
uv_signal_t
*
handle
,
int
signum
)
{
if
(
!
rt
->
js
)
return
;
ant_value_t
process_obj
=
js_get
(
rt
->
js
,
js_glob
(
rt
->
js
),
"process"
);
if
(
!
is_special_object
(
process_obj
))
return
;
ant_value_t
stdout_obj
=
js_get
(
rt
->
js
,
process_obj
,
"stdout"
);
if
(
!
is_special_object
(
stdout_obj
))
return
;
emit_stdio_event
(
&
stdout_events
,
"resize"
,
NULL
,
0
);
}
#endif
static
void
start_sigwinch_handler
(
void
)
{
#ifndef _WIN32
if
(
sigwinch_initialized
)
return
;
uv_loop_t
*
loop
=
uv_default_loop
();
if
(
uv_signal_init
(
loop
,
&
sigwinch_handle
)
!=
0
)
return
;
if
(
uv_signal_start
(
&
sigwinch_handle
,
on_sigwinch
,
SIGWINCH
)
!=
0
)
{
uv_close
((
uv_handle_t
*
)
&
sigwinch_handle
,
NULL
);
return
;
}
uv_unref
((
uv_handle_t
*
)
&
sigwinch_handle
);
sigwinch_initialized
=
true
;
#endif
}
static
ant_value_t
js_stdin_set_raw_mode
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
bool
enable
=
nargs
>
0
?
js_truthy
(
js
,
args
[
0
])
:
true
;
return
js_bool
(
stdin_set_raw_mode
(
enable
));
}
static
ant_value_t
js_stdin_set_encoding
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
ant_value_t
encoding
=
nargs
>
0
&&
!
is_undefined
(
args
[
0
])
?
args
[
0
]
:
js_mkstr
(
js
,
"utf8"
,
4
);
ant_value_t
decoder
=
string_decoder_create
(
js
,
encoding
);
ant_value_t
encoding_str
=
0
;
if
(
is_err
(
decoder
))
return
decoder
;
encoding_str
=
js_tostring_val
(
js
,
encoding
);
if
(
is_err
(
encoding_str
))
return
encoding_str
;
stdin_state
.
decoder
=
decoder
;
js_set
(
js
,
this_obj
,
"encoding"
,
encoding_str
);
return
this_obj
;
}
static
ant_value_t
js_stdin_resume
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
stdin_start_reading
();
return
js_getthis
(
js
);
}
static
ant_value_t
js_stdin_pause
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
stdin_stop_reading
();
return
js_getthis
(
js
);
}
static
ant_value_t
js_stdin_on
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
<
2
)
return
this_obj
;
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
||
vtype
(
args
[
1
])
!=
T_FUNC
)
return
this_obj
;
ProcessEventType
*
evt
=
find_or_create_event
(
&
stdin_events
,
event
);
if
(
!
ensure_listener_capacity
(
evt
))
return
this_obj
;
evt
->
listeners
[
evt
->
listener_count
].
listener
=
args
[
1
];
evt
->
listeners
[
evt
->
listener_count
].
once
=
false
;
evt
->
listener_count
++
;
if
(
strcmp
(
event
,
"data"
)
==
0
)
stdin_start_reading
();
return
this_obj
;
}
static
ant_value_t
js_stdin_remove_all_listeners
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
<
1
)
{
ProcessEventType
*
evt
,
*
tmp
;
HASH_ITER
(
hh
,
stdin_events
,
evt
,
tmp
)
{
free_event_type
(
&
stdin_events
,
evt
);
}
stdin_stop_reading
();
return
this_obj
;
}
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
)
return
this_obj
;
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
stdin_events
,
event
,
evt
);
if
(
evt
)
free_event_type
(
&
stdin_events
,
evt
);
if
(
strcmp
(
event
,
"data"
)
==
0
)
stdin_stop_reading
();
return
this_obj
;
}
static
ant_value_t
js_stdin_remove_listener
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
<
2
)
return
this_obj
;
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
)
return
this_obj
;
bool
now_empty
=
remove_listener_from_events
(
&
stdin_events
,
event
,
args
[
1
]);
if
(
now_empty
&&
strcmp
(
event
,
"data"
)
==
0
)
stdin_stop_reading
();
return
this_obj
;
}
static
ant_value_t
process_write_stream
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
,
FILE
*
stream
,
int
fd
)
{
if
(
nargs
<
1
)
return
js_false
;
size_t
len
=
0
;
char
*
data
=
js_getstr
(
js
,
args
[
0
],
&
len
);
ant_output_stream_t
*
out
=
NULL
;
if
(
!
data
)
return
js_false
;
if
(
uv_guess_handle
(
fd
)
==
UV_TTY
)
{
return
js_bool
(
tty_ctrl_write_fd
(
fd
,
data
,
len
));
}
out
=
ant_output_stream
(
stream
);
ant_output_stream_begin
(
out
);
if
(
!
ant_output_stream_append
(
out
,
data
,
len
))
return
js_false
;
return
ant_output_stream_flush
(
out
)
?
js_true
:
js_false
;
}
static
ant_value_t
js_stdout_write
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
process_write_stream
(
js
,
args
,
nargs
,
stdout
,
STDOUT_FILENO
);
}
static
ant_value_t
js_stdout_on
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
<
2
)
return
this_obj
;
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
||
vtype
(
args
[
1
])
!=
T_FUNC
)
return
this_obj
;
ProcessEventType
*
evt
=
find_or_create_event
(
&
stdout_events
,
event
);
if
(
!
ensure_listener_capacity
(
evt
))
return
this_obj
;
evt
->
listeners
[
evt
->
listener_count
].
listener
=
args
[
1
];
evt
->
listeners
[
evt
->
listener_count
].
once
=
false
;
evt
->
listener_count
++
;
if
(
strcmp
(
event
,
"resize"
)
==
0
)
start_sigwinch_handler
();
return
this_obj
;
}
static
ant_value_t
js_stdout_once
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
<
2
)
return
this_obj
;
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
||
vtype
(
args
[
1
])
!=
T_FUNC
)
return
this_obj
;
ProcessEventType
*
evt
=
find_or_create_event
(
&
stdout_events
,
event
);
if
(
!
ensure_listener_capacity
(
evt
))
return
this_obj
;
evt
->
listeners
[
evt
->
listener_count
].
listener
=
args
[
1
];
evt
->
listeners
[
evt
->
listener_count
].
once
=
true
;
evt
->
listener_count
++
;
if
(
strcmp
(
event
,
"resize"
)
==
0
)
start_sigwinch_handler
();
return
this_obj
;
}
static
ant_value_t
js_stdout_remove_all_listeners
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
<
1
)
{
ProcessEventType
*
evt
,
*
tmp
;
HASH_ITER
(
hh
,
stdout_events
,
evt
,
tmp
)
{
free_event_type
(
&
stdout_events
,
evt
);
}
return
this_obj
;
}
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
)
return
this_obj
;
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
stdout_events
,
event
,
evt
);
if
(
evt
)
free_event_type
(
&
stdout_events
,
evt
);
return
this_obj
;
}
static
ant_value_t
js_stdout_remove_listener
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
<
2
)
return
this_obj
;
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
)
return
this_obj
;
remove_listener_from_events
(
&
stdout_events
,
event
,
args
[
1
]);
return
this_obj
;
}
static
ant_value_t
js_stdout_get_window_size
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
int
rows
=
0
,
cols
=
0
;
get_tty_size
(
STDOUT_FILENO
,
&
rows
,
&
cols
);
ant_value_t
arr
=
js_mkarr
(
js
);
js_arr_push
(
js
,
arr
,
js_mknum
(
cols
));
js_arr_push
(
js
,
arr
,
js_mknum
(
rows
));
return
arr
;
}
static
ant_value_t
js_stdout_rows_getter
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
int
rows
=
0
,
cols
=
0
;
get_tty_size
(
STDOUT_FILENO
,
&
rows
,
&
cols
);
return
js_mknum
(
rows
);
}
static
ant_value_t
js_stdout_columns_getter
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
int
rows
=
0
,
cols
=
0
;
get_tty_size
(
STDOUT_FILENO
,
&
rows
,
&
cols
);
return
js_mknum
(
cols
);
}
static
ant_value_t
js_stderr_write
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
process_write_stream
(
js
,
args
,
nargs
,
stderr
,
STDERR_FILENO
);
}
static
ant_value_t
js_stderr_on
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
<
2
)
return
this_obj
;
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
||
vtype
(
args
[
1
])
!=
T_FUNC
)
return
this_obj
;
ProcessEventType
*
evt
=
find_or_create_event
(
&
stderr_events
,
event
);
if
(
!
ensure_listener_capacity
(
evt
))
return
this_obj
;
evt
->
listeners
[
evt
->
listener_count
].
listener
=
args
[
1
];
evt
->
listeners
[
evt
->
listener_count
].
once
=
false
;
evt
->
listener_count
++
;
return
this_obj
;
}
static
ant_value_t
js_stderr_once
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
<
2
)
return
this_obj
;
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
||
vtype
(
args
[
1
])
!=
T_FUNC
)
return
this_obj
;
ProcessEventType
*
evt
=
find_or_create_event
(
&
stderr_events
,
event
);
if
(
!
ensure_listener_capacity
(
evt
))
return
this_obj
;
evt
->
listeners
[
evt
->
listener_count
].
listener
=
args
[
1
];
evt
->
listeners
[
evt
->
listener_count
].
once
=
true
;
evt
->
listener_count
++
;
return
this_obj
;
}
static
ant_value_t
js_stderr_remove_all_listeners
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
<
1
)
{
ProcessEventType
*
evt
,
*
tmp
;
HASH_ITER
(
hh
,
stderr_events
,
evt
,
tmp
)
{
free_event_type
(
&
stderr_events
,
evt
);
}
return
this_obj
;
}
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
)
return
this_obj
;
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
stderr_events
,
event
,
evt
);
if
(
evt
)
free_event_type
(
&
stderr_events
,
evt
);
return
this_obj
;
}
static
ant_value_t
js_stderr_remove_listener
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
this_obj
=
js_getthis
(
js
);
if
(
nargs
<
2
)
return
this_obj
;
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
)
return
this_obj
;
remove_listener_from_events
(
&
stderr_events
,
event
,
args
[
1
]);
return
this_obj
;
}
static
ant_value_t
process_uptime
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
uint64_t
now
=
uv_hrtime
();
double
seconds
=
(
double
)(
now
-
process_start_time
)
/
1e9
;
return
js_mknum
(
seconds
);
}
static
ant_value_t
process_hrtime
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
uint64_t
now
=
uv_hrtime
();
if
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_ARR
)
{
ant_value_t
prev_sec
=
js_get
(
js
,
args
[
0
],
"0"
);
ant_value_t
prev_nsec
=
js_get
(
js
,
args
[
0
],
"1"
);
if
(
vtype
(
prev_sec
)
==
T_NUM
&&
vtype
(
prev_nsec
)
==
T_NUM
)
{
uint64_t
prev
=
(
uint64_t
)
js_getnum
(
prev_sec
)
*
1000000000ULL
+
(
uint64_t
)
js_getnum
(
prev_nsec
);
now
=
now
-
prev
;
}
}
ant_value_t
arr
=
js_mkarr
(
js
);
uint64_t
secs
=
now
/
1000000000ULL
;
uint64_t
nsecs
=
now
%
1000000000ULL
;
js_arr_push
(
js
,
arr
,
js_mknum
((
double
)
secs
));
js_arr_push
(
js
,
arr
,
js_mknum
((
double
)
nsecs
));
return
arr
;
}
static
ant_value_t
process_hrtime_bigint
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
uint64_t
now
=
uv_hrtime
();
char
buf
[
32
];
snprintf
(
buf
,
sizeof
(
buf
),
"%llu"
,
(
unsigned
long
long
)
now
);
return
js_mkbigint
(
js
,
buf
,
strlen
(
buf
),
false
);
}
static
ant_value_t
process_memory_usage
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
ant_value_t
obj
=
js_mkobj
(
js
);
size_t
rss
=
0
;
uv_resident_set_memory
(
&
rss
);
js_set
(
js
,
obj
,
"rss"
,
js_mknum
((
double
)
rss
));
#ifdef _WIN32
PROCESS_MEMORY_COUNTERS_EX
pmc
;
if
(
GetProcessMemoryInfo
(
GetCurrentProcess
(),
(
PROCESS_MEMORY_COUNTERS
*
)
&
pmc
,
sizeof
(
pmc
)))
{
js_set
(
js
,
obj
,
"heapTotal"
,
js_mknum
((
double
)
pmc
.
WorkingSetSize
));
js_set
(
js
,
obj
,
"heapUsed"
,
js_mknum
((
double
)
pmc
.
PrivateUsage
));
}
else
{
js_set
(
js
,
obj
,
"heapTotal"
,
js_mknum
(
0
));
js_set
(
js
,
obj
,
"heapUsed"
,
js_mknum
(
0
));
}
#else
struct
rusage
usage
;
if
(
getrusage
(
RUSAGE_SELF
,
&
usage
)
==
0
)
{
js_set
(
js
,
obj
,
"heapTotal"
,
js_mknum
((
double
)
rss
));
js_set
(
js
,
obj
,
"heapUsed"
,
js_mknum
((
double
)
rss
));
}
else
{
js_set
(
js
,
obj
,
"heapTotal"
,
js_mknum
(
0
));
js_set
(
js
,
obj
,
"heapUsed"
,
js_mknum
(
0
));
}
#endif
js_set
(
js
,
obj
,
"external"
,
js_mknum
(
0
));
js_set
(
js
,
obj
,
"arrayBuffers"
,
js_mknum
(
0
));
return
obj
;
}
static
ant_value_t
process_memory_usage_rss
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
size_t
rss
=
0
;
uv_resident_set_memory
(
&
rss
);
return
js_mknum
((
double
)
rss
);
}
static
ant_value_t
process_cpu_usage
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
obj
=
js_mkobj
(
js
);
uv_rusage_t
rusage
;
if
(
uv_getrusage
(
&
rusage
)
==
0
)
{
int64_t
user_usec
=
rusage
.
ru_utime
.
tv_sec
*
1000000L
L
+
rusage
.
ru_utime
.
tv_usec
;
int64_t
sys_usec
=
rusage
.
ru_stime
.
tv_sec
*
1000000L
L
+
rusage
.
ru_stime
.
tv_usec
;
if
(
nargs
>
0
&&
is_special_object
(
args
[
0
]))
{
ant_value_t
prev_user
=
js_get
(
js
,
args
[
0
],
"user"
);
ant_value_t
prev_system
=
js_get
(
js
,
args
[
0
],
"system"
);
if
(
vtype
(
prev_user
)
==
T_NUM
)
user_usec
-=
(
int64_t
)
js_getnum
(
prev_user
);
if
(
vtype
(
prev_system
)
==
T_NUM
)
sys_usec
-=
(
int64_t
)
js_getnum
(
prev_system
);
}
js_set
(
js
,
obj
,
"user"
,
js_mknum
((
double
)
user_usec
));
js_set
(
js
,
obj
,
"system"
,
js_mknum
((
double
)
sys_usec
));
}
else
{
js_set
(
js
,
obj
,
"user"
,
js_mknum
(
0
));
js_set
(
js
,
obj
,
"system"
,
js_mknum
(
0
));
}
return
obj
;
}
static
ant_value_t
process_kill
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"process.kill requires at least 1 argument"
);
if
(
vtype
(
args
[
0
])
!=
T_NUM
)
return
js_mkerr
(
js
,
"pid must be a number"
);
int
pid
=
(
int
)
js_getnum
(
args
[
0
]);
int
sig
=
SIGTERM
;
if
(
nargs
>
1
)
{
if
(
vtype
(
args
[
1
])
==
T_NUM
)
{
sig
=
(
int
)
js_getnum
(
args
[
1
]);
}
else
if
(
vtype
(
args
[
1
])
==
T_STR
)
{
char
*
sig_name
=
js_getstr
(
js
,
args
[
1
],
NULL
);
if
(
sig_name
)
{
int
signum
=
get_signal_number
(
sig_name
);
if
(
signum
>
0
)
sig
=
signum
;
else
return
js_mkerr
(
js
,
"Unknown signal"
);
}
}
}
int
result
=
uv_kill
(
pid
,
sig
);
if
(
result
!=
0
)
return
js_mkerr
(
js
,
"Failed to send signal"
);
return
js_true
;
}
static
ant_value_t
process_abort
(
ant_params_t
)
{
abort
();
return
js_mkundef
();
}
static
ant_value_t
process_chdir
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"process.chdir requires 1 argument"
);
char
*
dir
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
dir
)
return
js_mkerr
(
js
,
"directory must be a string"
);
int
result
=
uv_chdir
(
dir
);
if
(
result
!=
0
)
return
js_mkerr
(
js
,
"ENOENT: no such file or directory, chdir"
);
return
js_mkundef
();
}
static
ant_value_t
process_umask
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
#ifdef _WIN32
(
void
)
args
;
(
void
)
nargs
;
return
js_mknum
(
0
);
#else
if
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_NUM
)
{
int
new_mask
=
(
int
)
js_getnum
(
args
[
0
]);
int
old_mask
=
umask
((
mode_t
)
new_mask
);
return
js_mknum
(
old_mask
);
}
int
cur
=
umask
(
0
);
umask
((
mode_t
)
cur
);
return
js_mknum
(
cur
);
#endif
}
#ifndef _WIN32
static
ant_value_t
process_getuid
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
return
js_mknum
((
double
)
getuid
());
}
static
ant_value_t
process_geteuid
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
return
js_mknum
((
double
)
geteuid
());
}
static
ant_value_t
process_getgid
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
return
js_mknum
((
double
)
getgid
());
}
static
ant_value_t
process_getegid
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
return
js_mknum
((
double
)
getegid
());
}
static
ant_value_t
process_getgroups
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
int
ngroups
=
getgroups
(
0
,
NULL
);
if
(
ngroups
<
0
)
return
js_mkarr
(
js
);
gid_t
*
groups
=
malloc
(
sizeof
(
gid_t
)
*
(
size_t
)
ngroups
);
if
(
!
groups
)
return
js_mkarr
(
js
);
ngroups
=
getgroups
(
ngroups
,
groups
);
ant_value_t
arr
=
js_mkarr
(
js
);
for
(
int
i
=
0
;
i
<
ngroups
;
i
++
)
{
js_arr_push
(
js
,
arr
,
js_mknum
((
double
)
groups
[
i
]));
}
free
(
groups
);
return
arr
;
}
static
ant_value_t
process_setuid
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"process.setuid requires 1 argument"
);
uid_t
uid
;
if
(
vtype
(
args
[
0
])
==
T_NUM
)
{
uid
=
(
uid_t
)
js_getnum
(
args
[
0
]);
}
else
if
(
vtype
(
args
[
0
])
==
T_STR
)
{
char
*
name
=
js_getstr
(
js
,
args
[
0
],
NULL
);
struct
passwd
*
pwd
=
getpwnam
(
name
);
if
(
!
pwd
)
return
js_mkerr
(
js
,
"setuid user not found"
);
uid
=
pwd
->
pw_uid
;
}
else
{
return
js_mkerr
(
js
,
"uid must be a number or string"
);
}
if
(
setuid
(
uid
)
!=
0
)
return
js_mkerr
(
js
,
"setuid failed"
);
return
js_mkundef
();
}
static
ant_value_t
process_setgid
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"process.setgid requires 1 argument"
);
gid_t
gid
;
if
(
vtype
(
args
[
0
])
==
T_NUM
)
{
gid
=
(
gid_t
)
js_getnum
(
args
[
0
]);
}
else
if
(
vtype
(
args
[
0
])
==
T_STR
)
{
char
*
name
=
js_getstr
(
js
,
args
[
0
],
NULL
);
struct
group
*
grp
=
getgrnam
(
name
);
if
(
!
grp
)
return
js_mkerr
(
js
,
"setgid group not found"
);
gid
=
grp
->
gr_gid
;
}
else
{
return
js_mkerr
(
js
,
"gid must be a number or string"
);
}
if
(
setgid
(
gid
)
!=
0
)
return
js_mkerr
(
js
,
"setgid failed"
);
return
js_mkundef
();
}
static
ant_value_t
process_seteuid
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"process.seteuid requires 1 argument"
);
uid_t
uid
;
if
(
vtype
(
args
[
0
])
==
T_NUM
)
{
uid
=
(
uid_t
)
js_getnum
(
args
[
0
]);
}
else
if
(
vtype
(
args
[
0
])
==
T_STR
)
{
char
*
name
=
js_getstr
(
js
,
args
[
0
],
NULL
);
struct
passwd
*
pwd
=
getpwnam
(
name
);
if
(
!
pwd
)
return
js_mkerr
(
js
,
"seteuid user not found"
);
uid
=
pwd
->
pw_uid
;
}
else
{
return
js_mkerr
(
js
,
"uid must be a number or string"
);
}
if
(
seteuid
(
uid
)
!=
0
)
return
js_mkerr
(
js
,
"seteuid failed"
);
return
js_mkundef
();
}
static
ant_value_t
process_setegid
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"process.setegid requires 1 argument"
);
gid_t
gid
;
if
(
vtype
(
args
[
0
])
==
T_NUM
)
{
gid
=
(
gid_t
)
js_getnum
(
args
[
0
]);
}
else
if
(
vtype
(
args
[
0
])
==
T_STR
)
{
char
*
name
=
js_getstr
(
js
,
args
[
0
],
NULL
);
struct
group
*
grp
=
getgrnam
(
name
);
if
(
!
grp
)
return
js_mkerr
(
js
,
"setegid group not found"
);
gid
=
grp
->
gr_gid
;
}
else
{
return
js_mkerr
(
js
,
"gid must be a number or string"
);
}
if
(
setegid
(
gid
)
!=
0
)
return
js_mkerr
(
js
,
"setegid failed"
);
return
js_mkundef
();
}
static
ant_value_t
process_setgroups
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
vtype
(
args
[
0
])
!=
T_ARR
)
{
return
js_mkerr
(
js
,
"process.setgroups requires an array"
);
}
ant_value_t
len_val
=
js_get
(
js
,
args
[
0
],
"length"
);
int
len
=
(
int
)
js_getnum
(
len_val
);
gid_t
*
groups
=
malloc
(
sizeof
(
gid_t
)
*
(
size_t
)
len
);
if
(
!
groups
)
return
js_mkerr
(
js
,
"allocation failed"
);
for
(
int
i
=
0
;
i
<
len
;
i
++
)
{
char
idx
[
16
];
snprintf
(
idx
,
sizeof
(
idx
),
"%d"
,
i
);
ant_value_t
val
=
js_get
(
js
,
args
[
0
],
idx
);
if
(
vtype
(
val
)
==
T_NUM
)
{
groups
[
i
]
=
(
gid_t
)
js_getnum
(
val
);
}
else
if
(
vtype
(
val
)
==
T_STR
)
{
char
*
name
=
js_getstr
(
js
,
val
,
NULL
);
struct
group
*
grp
=
getgrnam
(
name
);
if
(
!
grp
)
{
free
(
groups
);
return
js_mkerr
(
js
,
"group not found"
);
}
groups
[
i
]
=
grp
->
gr_gid
;
}
else
{
free
(
groups
);
return
js_mkerr
(
js
,
"group id must be number or string"
);
}
}
if
(
setgroups
(
len
,
groups
)
!=
0
)
{
free
(
groups
);
return
js_mkerr
(
js
,
"setgroups failed"
);
}
free
(
groups
);
return
js_mkundef
();
}
static
ant_value_t
process_initgroups
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkerr
(
js
,
"process.initgroups requires 2 arguments"
);
char
*
user
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
user
)
return
js_mkerr
(
js
,
"user must be a string"
);
gid_t
gid
;
if
(
vtype
(
args
[
1
])
==
T_NUM
)
{
gid
=
(
gid_t
)
js_getnum
(
args
[
1
]);
}
else
if
(
vtype
(
args
[
1
])
==
T_STR
)
{
char
*
name
=
js_getstr
(
js
,
args
[
1
],
NULL
);
struct
group
*
grp
=
getgrnam
(
name
);
if
(
!
grp
)
return
js_mkerr
(
js
,
"group not found"
);
gid
=
grp
->
gr_gid
;
}
else
{
return
js_mkerr
(
js
,
"gid must be a number or string"
);
}
if
(
initgroups
(
user
,
gid
)
!=
0
)
return
js_mkerr
(
js
,
"initgroups failed"
);
return
js_mkundef
();
}
#endif
static
ant_value_t
env_getter
(
ant_t
*
js
,
ant_value_t
obj
,
const
char
*
key
,
size_t
key_len
)
{
CSTR_BUF
(
buf
,
256
);
char
*
key_str
=
CSTR_INIT
(
buf
,
key
,
key_len
);
if
(
!
key_str
)
return
js_mkundef
();
char
*
value
=
getenv
(
key_str
);
cstr_free
(
&
buf
);
if
(
value
==
NULL
)
return
js_mkundef
();
return
js_mkstr
(
js
,
value
,
strlen
(
value
));
}
static
bool
env_setter
(
ant_t
*
js
,
ant_value_t
obj
,
const
char
*
key
,
size_t
key_len
,
ant_value_t
value
)
{
ant_value_t
str_val
=
coerce_to_str
(
js
,
value
);
if
(
is_err
(
str_val
))
return
false
;
setprop_cstr
(
js
,
obj
,
key
,
key_len
,
str_val
);
CSTR_BUF
(
buf
,
256
);
char
*
key_str
=
CSTR_INIT
(
buf
,
key
,
key_len
);
if
(
key_str
)
{
size_t
val_len
;
char
*
val_str
=
js_getstr
(
js
,
str_val
,
&
val_len
);
if
(
val_str
)
setenv
(
key_str
,
val_str
,
1
);
cstr_free
(
&
buf
);
}
return
true
;
}
static
bool
env_deleter
(
ant_t
*
js
,
ant_value_t
obj
,
const
char
*
key
,
size_t
key_len
)
{
CSTR_BUF
(
buf
,
256
);
char
*
key_str
=
CSTR_INIT
(
buf
,
key
,
key_len
);
if
(
key_str
)
{
unsetenv
(
key_str
);
cstr_free
(
&
buf
);
}
return
true
;
}
static
void
load_dotenv_file
(
ant_t
*
js
,
ant_value_t
env_obj
)
{
FILE
*
fp
=
fopen
(
".env"
,
"r"
);
if
(
fp
==
NULL
)
return
;
char
line
[
1024
];
while
(
fgets
(
line
,
sizeof
(
line
),
fp
)
!=
NULL
)
{
size_t
len
=
strlen
(
line
);
if
(
len
>
0
&&
line
[
len
-
1
]
==
'\n'
)
{
line
[
len
-
1
]
=
'\0'
;
len
--
;
}
if
(
len
>
0
&&
line
[
len
-
1
]
==
'\r'
)
{
line
[
len
-
1
]
=
'\0'
;
len
--
;
}
if
(
len
==
0
||
line
[
0
]
==
'#'
)
continue
;
char
*
equals
=
strchr
(
line
,
'='
);
if
(
equals
==
NULL
)
continue
;
*
equals
=
'\0'
;
char
*
key
=
line
;
char
*
value
=
equals
+
1
;
while
(
*
key
==
' '
||
*
key
==
'\t'
)
key
++
;
char
*
key_end
=
key
+
strlen
(
key
)
-
1
;
while
(
key_end
>
key
&&
(
*
key_end
==
' '
||
*
key_end
==
'\t'
))
{
*
key_end
=
'\0'
;
key_end
--
;
}
while
(
*
value
==
' '
||
*
value
==
'\t'
)
value
++
;
char
*
value_end
=
value
+
strlen
(
value
)
-
1
;
while
(
value_end
>
value
&&
(
*
value_end
==
' '
||
*
value_end
==
'\t'
))
{
*
value_end
=
'\0'
;
value_end
--
;
}
if
(
strlen
(
value
)
>=
2
&&
((
value
[
0
]
==
'"'
&&
value
[
strlen
(
value
)
-
1
]
==
'"'
)
||
(
value
[
0
]
==
'\''
&&
value
[
strlen
(
value
)
-
1
]
==
'\''
)))
{
value
[
strlen
(
value
)
-
1
]
=
'\0'
;
value
++
;
}
js_set
(
js
,
env_obj
,
key
,
js_mkstr
(
js
,
value
,
strlen
(
value
)));
}
fclose
(
fp
);
}
static
ant_value_t
process_exit
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
int
code
=
0
;
if
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_NUM
)
{
code
=
(
int
)
js_getnum
(
args
[
0
]);
}
exit
(
code
);
return
js_mkundef
();
}
typedef
struct
{
char
*
buf
;
size_t
pos
;
size_t
cap
;
}
env_str_ctx
;
typedef
void
(
*
env_iter_cb
)(
ant_t
*
js
,
const
char
*
key
,
size_t
key_len
,
const
char
*
value
,
size_t
val_len
,
void
*
ctx
);
static
void
env_foreach
(
ant_t
*
js
,
ant_value_t
env_obj
,
env_iter_cb
cb
,
void
*
ctx
)
{
for
(
char
**
env
=
environ
;
*
env
!=
NULL
;
env
++
)
{
char
*
entry
=
*
env
;
char
*
equals
=
strchr
(
entry
,
'='
);
if
(
equals
==
NULL
)
continue
;
size_t
key_len
=
(
size_t
)(
equals
-
entry
);
char
*
value
=
equals
+
1
;
cb
(
js
,
entry
,
key_len
,
value
,
strlen
(
value
),
ctx
);
}
ant_iter_t
iter
=
js_prop_iter_begin
(
js
,
env_obj
);
const
char
*
key
;
size_t
key_len
;
ant_value_t
value
;
while
(
js_prop_iter_next
(
&
iter
,
&
key
,
&
key_len
,
&
value
))
{
if
(
vtype
(
value
)
!=
T_STR
)
continue
;
CSTR_BUF
(
buf
,
256
);
char
*
key_str
=
CSTR_INIT
(
buf
,
key
,
key_len
);
if
(
!
key_str
)
continue
;
if
(
getenv
(
key_str
))
{
cstr_free
(
&
buf
);
continue
;
}
cstr_free
(
&
buf
);
size_t
val_len
;
char
*
val_str
=
js_getstr
(
js
,
value
,
&
val_len
);
cb
(
js
,
key
,
key_len
,
val_str
?
val_str
:
""
,
val_str
?
val_len
:
0
,
ctx
);
}
js_prop_iter_end
(
&
iter
);
}
static
void
env_to_object_cb
(
ant_t
*
js
,
const
char
*
key
,
size_t
key_len
,
const
char
*
value
,
size_t
val_len
,
void
*
ctx
)
{
ant_value_t
obj
=
*
(
ant_value_t
*
)
ctx
;
CSTR_BUF
(
buf
,
256
);
char
*
key_str
=
CSTR_INIT
(
buf
,
key
,
key_len
);
if
(
!
key_str
)
return
;
js_set
(
js
,
obj
,
key_str
,
js_mkstr
(
js
,
value
,
val_len
));
cstr_free
(
&
buf
);
}
static
ant_value_t
env_to_object
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
obj
=
js_mkobj
(
js
);
env_foreach
(
js
,
js
->
this_val
,
env_to_object_cb
,
&
obj
);
return
obj
;
}
static
void
env_tostring_cb
(
ant_t
*
js
,
const
char
*
key
,
size_t
key_len
,
const
char
*
value
,
size_t
val_len
,
void
*
ctx
)
{
env_str_ctx
*
c
=
ctx
;
size_t
entry_len
=
key_len
+
1
+
val_len
;
if
(
c
->
pos
+
entry_len
+
2
>=
c
->
cap
)
{
size_t
new_cap
=
c
->
cap
*
2
+
entry_len
;
char
*
new_buf
=
realloc
(
c
->
buf
,
new_cap
);
if
(
!
new_buf
)
return
;
c
->
buf
=
new_buf
;
c
->
cap
=
new_cap
;
}
if
(
c
->
pos
>
0
)
c
->
buf
[
c
->
pos
++
]
=
'\n'
;
memcpy
(
c
->
buf
+
c
->
pos
,
key
,
key_len
);
c
->
pos
+=
key_len
;
c
->
buf
[
c
->
pos
++
]
=
'='
;
memcpy
(
c
->
buf
+
c
->
pos
,
value
,
val_len
);
c
->
pos
+=
val_len
;
}
static
ant_value_t
env_toString
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
env_str_ctx
ctx
=
{
.
buf
=
malloc
(
4096
),
.
pos
=
0
,
.
cap
=
4096
};
if
(
!
ctx
.
buf
)
return
js_mkstr
(
js
,
""
,
0
);
env_foreach
(
js
,
js
->
this_val
,
env_tostring_cb
,
&
ctx
);
ctx
.
buf
[
ctx
.
pos
]
=
'\0'
;
ant_value_t
ret
=
js_mkstr
(
js
,
ctx
.
buf
,
ctx
.
pos
);
free
(
ctx
.
buf
);
return
ret
;
}
static
void
env_keys_cb
(
ant_t
*
js
,
const
char
*
key
,
size_t
key_len
,
const
char
*
value
,
size_t
val_len
,
void
*
ctx
)
{
ant_value_t
arr
=
*
(
ant_value_t
*
)
ctx
;
js_arr_push
(
js
,
arr
,
js_mkstr
(
js
,
key
,
key_len
));
}
static
ant_value_t
env_keys
(
ant_t
*
js
,
ant_value_t
obj
)
{
ant_value_t
arr
=
js_mkarr
(
js
);
env_foreach
(
js
,
obj
,
env_keys_cb
,
&
arr
);
return
arr
;
}
static
ant_value_t
process_cwd
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
char
cwd
[
4096
];
if
(
getcwd
(
cwd
,
sizeof
(
cwd
))
!=
NULL
)
{
return
js_mkstr
(
js
,
cwd
,
strlen
(
cwd
));
}
return
js_mkundef
();
}
static
ant_value_t
process_add
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
,
bool
once
,
bool
prepend
)
{
if
(
nargs
<
2
)
{
return
js_mkerr
(
js
,
once
?
"process.once requires 2 arguments"
:
"process.on requires 2 arguments"
);
}
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
)
return
js_mkerr
(
js
,
"event must be a string"
);
uint8_t
listener_type
=
vtype
(
args
[
1
]);
if
(
listener_type
!=
T_FUNC
&&
listener_type
!=
T_CFUNC
)
{
return
js_mkerr
(
js
,
"listener must be a function"
);
}
int
signum
=
get_signal_number
(
event
);
if
(
signum
>
0
)
start_signal_watch
(
signum
);
ProcessEventType
*
evt
=
find_or_create_event
(
&
process_events
,
event
);
if
(
!
ensure_listener_capacity
(
evt
))
return
js_mkerr
(
js
,
"failed to allocate listener"
);
if
(
prepend
&&
evt
->
listener_count
>
0
)
{
memmove
(
&
evt
->
listeners
[
1
],
&
evt
->
listeners
[
0
],
(
size_t
)
evt
->
listener_count
*
sizeof
(
ProcessEventListener
)
);
evt
->
listeners
[
0
].
listener
=
args
[
1
];
evt
->
listeners
[
0
].
once
=
once
;
}
else
{
evt
->
listeners
[
evt
->
listener_count
].
listener
=
args
[
1
];
evt
->
listeners
[
evt
->
listener_count
].
once
=
once
;
}
evt
->
listener_count
++
;
check_listener_warning
(
event
);
return
js_get
(
js
,
js_glob
(
js
),
"process"
);
}
static
ant_value_t
process_on
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
process_add
(
js
,
args
,
nargs
,
false
,
false
);
}
static
ant_value_t
process_once
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
process_add
(
js
,
args
,
nargs
,
true
,
false
);
}
static
ant_value_t
process_prepend_listener
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
process_add
(
js
,
args
,
nargs
,
false
,
true
);
}
static
ant_value_t
process_prepend_once_listener
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
process_add
(
js
,
args
,
nargs
,
true
,
true
);
}
static
ant_value_t
process_off
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
process_obj
=
js_get
(
js
,
js_glob
(
js
),
"process"
);
if
(
nargs
<
2
)
return
process_obj
;
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
)
return
process_obj
;
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
process_events
,
event
,
evt
);
if
(
!
evt
)
return
process_obj
;
for
(
int
i
=
0
;
i
<
evt
->
listener_count
;
i
++
)
{
if
(
evt
->
listeners
[
i
].
listener
==
args
[
1
])
{
for
(
int
j
=
i
;
j
<
evt
->
listener_count
-
1
;
j
++
)
{
evt
->
listeners
[
j
]
=
evt
->
listeners
[
j
+
1
];
}
evt
->
listener_count
--
;
break
;
}
}
if
(
evt
->
listener_count
==
0
)
{
int
signum
=
get_signal_number
(
event
);
if
(
signum
>
0
)
stop_signal_watch
(
signum
);
}
return
process_obj
;
}
static
ant_value_t
process_remove_all_listeners
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
process_obj
=
js_get
(
js
,
js_glob
(
js
),
"process"
);
if
(
nargs
>
0
&&
vtype
(
args
[
0
])
==
T_STR
)
{
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
event
)
{
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
process_events
,
event
,
evt
);
if
(
evt
)
{
int
signum
=
get_signal_number
(
event
);
if
(
signum
>
0
)
stop_signal_watch
(
signum
);
free_event_type
(
&
process_events
,
evt
);
}
}
}
else
{
ProcessEventType
*
evt
,
*
tmp
;
HASH_ITER
(
hh
,
process_events
,
evt
,
tmp
)
{
int
signum
=
get_signal_number
(
evt
->
event_type
);
if
(
signum
>
0
)
stop_signal_watch
(
signum
);
free_event_type
(
&
process_events
,
evt
);
}
}
return
process_obj
;
}
static
ant_value_t
process_emit
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_false
;
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
)
return
js_false
;
emit_process_event
(
event
,
nargs
>
1
?
&
args
[
1
]
:
NULL
,
nargs
-
1
);
return
js_true
;
}
static
bool
process_is_error_object
(
ant_value_t
value
)
{
if
(
is_err
(
value
))
return
true
;
return
is_object_type
(
value
)
&&
js_get_slot
(
value
,
SLOT_ERROR_BRAND
)
==
js_true
;
}
static
void
process_get_warning_options
(
ant_t
*
js
,
ant_value_t
options
,
const
char
**
type
,
const
char
**
code
,
const
char
**
detail
,
ant_offset_t
*
detail_len
)
{
if
(
!
is_object_type
(
options
))
return
;
ant_value_t
type_val
=
js_get
(
js
,
options
,
"type"
);
ant_value_t
code_val
=
js_get
(
js
,
options
,
"code"
);
ant_value_t
detail_val
=
js_get
(
js
,
options
,
"detail"
);
if
(
vtype
(
type_val
)
==
T_STR
)
*
type
=
js_getstr
(
js
,
type_val
,
NULL
);
if
(
vtype
(
code_val
)
==
T_STR
)
*
code
=
js_getstr
(
js
,
code_val
,
NULL
);
if
(
vtype
(
detail_val
)
==
T_STR
)
*
detail
=
(
const
char
*
)(
uintptr_t
)
vstr
(
js
,
detail_val
,
detail_len
);
}
static
ant_value_t
process_make_warning_object
(
ant_t
*
js
,
const
char
*
type
,
js_cstr_t
msg
,
const
char
*
code
,
const
char
*
detail
,
ant_offset_t
detail_len
)
{
ant_value_t
warning_obj
=
js_mkobj
(
js
);
js_set_proto_init
(
warning_obj
,
js_get_ctor_proto
(
js
,
"Error"
,
5
));
js_set_slot
(
warning_obj
,
SLOT_ERROR_BRAND
,
js_true
);
js_set
(
js
,
warning_obj
,
"name"
,
js_mkstr
(
js
,
type
,
strlen
(
type
)));
js_set
(
js
,
warning_obj
,
"message"
,
js_mkstr
(
js
,
msg
.
ptr
,
msg
.
len
));
if
(
code
)
js_set
(
js
,
warning_obj
,
"code"
,
js_mkstr
(
js
,
code
,
strlen
(
code
)));
if
(
detail
)
js_set
(
js
,
warning_obj
,
"detail"
,
js_mkstr
(
js
,
detail
,
detail_len
));
js_capture_stack
(
js
,
warning_obj
);
return
warning_obj
;
}
static
ant_value_t
process_emit_warning
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkundef
();
ant_value_t
warning
=
args
[
0
];
const
char
*
type
=
"Warning"
;
const
char
*
code
=
NULL
;
const
char
*
detail
=
NULL
;
ant_offset_t
detail_len
=
0
;
if
(
nargs
>=
2
)
{
if
(
vtype
(
args
[
1
])
==
T_STR
)
type
=
js_getstr
(
js
,
args
[
1
],
NULL
);
else
process_get_warning_options
(
js
,
args
[
1
],
&
type
,
&
code
,
&
detail
,
&
detail_len
);
}
if
(
nargs
>=
3
&&
vtype
(
args
[
2
])
==
T_STR
)
code
=
js_getstr
(
js
,
args
[
2
],
NULL
);
char
msg_buf
[
512
];
js_cstr_t
msg
=
{
0
};
ant_value_t
warning_event_arg
=
warning
;
bool
is_error
=
process_is_error_object
(
warning
);
if
(
is_error
)
{
ant_value_t
warning_obj
=
js_as_obj
(
warning
);
ant_offset_t
prop_len
=
0
;
const
char
*
name_prop
=
get_str_prop
(
js
,
warning_obj
,
"name"
,
4
,
&
prop_len
);
if
(
name_prop
)
type
=
name_prop
;
const
char
*
message_prop
=
get_str_prop
(
js
,
warning_obj
,
"message"
,
7
,
&
prop_len
);
msg
.
ptr
=
message_prop
?
message_prop
:
""
;
msg
.
len
=
message_prop
?
prop_len
:
0
;
msg
.
needs_free
=
false
;
code
=
get_str_prop
(
js
,
warning_obj
,
"code"
,
4
,
NULL
);
detail
=
get_str_prop
(
js
,
warning_obj
,
"detail"
,
6
,
&
detail_len
);
warning_event_arg
=
warning_obj
;
}
else
{
msg
=
js_to_cstr
(
js
,
warning
,
msg_buf
,
sizeof
(
msg_buf
));
warning_event_arg
=
process_make_warning_object
(
js
,
type
,
msg
,
code
,
detail
,
detail_len
);
}
fprintf
(
stderr
,
"(%s:%d) "
,
"ant"
,
(
int
)
getpid
());
if
(
code
)
fprintf
(
stderr
,
"[%s] "
,
code
);
fprintf
(
stderr
,
"%s: %.*s
\n
"
,
type
?
type
:
"Warning"
,
(
int
)
msg
.
len
,
msg
.
ptr
);
if
(
detail
)
fprintf
(
stderr
,
"%.*s
\n
"
,
(
int
)
detail_len
,
detail
);
emit_process_event
(
"warning"
,
&
warning_event_arg
,
1
);
if
(
msg
.
needs_free
)
free
((
void
*
)
msg
.
ptr
);
return
js_mkundef
();
}
static
ant_value_t
process_listener_count
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mknum
(
0
);
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
)
return
js_mknum
(
0
);
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
process_events
,
event
,
evt
);
return
js_mknum
(
evt
?
evt
->
listener_count
:
0
);
}
static
ant_value_t
process_listeners_impl
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
,
bool
raw
)
{
(
void
)
raw
;
ant_value_t
result
=
js_mkarr
(
js
);
if
(
nargs
<
1
)
return
result
;
char
*
event
=
js_getstr
(
js
,
args
[
0
],
NULL
);
if
(
!
event
)
return
result
;
ProcessEventType
*
evt
=
NULL
;
HASH_FIND_STR
(
process_events
,
event
,
evt
);
if
(
!
evt
)
return
result
;
for
(
int
i
=
0
;
i
<
evt
->
listener_count
;
i
++
)
{
js_arr_push
(
js
,
result
,
evt
->
listeners
[
i
].
listener
);
}
return
result
;
}
static
ant_value_t
process_listeners
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
process_listeners_impl
(
js
,
args
,
nargs
,
false
);
}
static
ant_value_t
process_raw_listeners
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
process_listeners_impl
(
js
,
args
,
nargs
,
true
);
}
static
ant_value_t
process_event_names
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
(
void
)
args
;
(
void
)
nargs
;
ant_value_t
result
=
js_mkarr
(
js
);
ProcessEventType
*
evt
=
NULL
;
ProcessEventType
*
tmp
=
NULL
;
HASH_ITER
(
hh
,
process_events
,
evt
,
tmp
)
{
if
(
evt
->
listener_count
>
0
)
{
js_arr_push
(
js
,
result
,
js_mkstr
(
js
,
evt
->
event_type
,
strlen
(
evt
->
event_type
)));
}
}
return
result
;
}
static
ant_value_t
process_set_max_listeners
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr
(
js
,
"setMaxListeners requires 1 argument"
);
if
(
vtype
(
args
[
0
])
!=
T_NUM
)
return
js_mkerr
(
js
,
"n must be a number"
);
int
n
=
(
int
)
js_getnum
(
args
[
0
]);
if
(
n
<
0
)
return
js_mkerr
(
js
,
"n must be non-negative"
);
max_listeners
=
n
;
return
js_get
(
js
,
js_glob
(
js
),
"process"
);
}
static
ant_value_t
process_get_max_listeners
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
return
js_mknum
(
max_listeners
);
}
static
ant_value_t
process_next_tick
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
)
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"process.nextTick requires a callback"
);
ant_value_t
cb
=
args
[
0
];
if
(
vtype
(
cb
)
!=
T_FUNC
&&
vtype
(
cb
)
!=
T_CFUNC
)
return
js_mkerr_typed
(
js
,
JS_ERR_TYPE
,
"process.nextTick callback is not a function"
);
if
(
nargs
<=
1
)
queue_next_tick
(
js
,
cb
);
else
queue_next_tick_with_args
(
js
,
cb
,
args
+
1
,
nargs
-
1
);
return
js_mkundef
();
}
static
void
process_set_methods
(
ant_t
*
js
,
ant_value_t
obj
,
bool
include_event_methods
)
{
js_set
(
js
,
obj
,
"exit"
,
js_mkfun
(
process_exit
));
js_set
(
js
,
obj
,
"cwd"
,
js_mkfun
(
process_cwd
));
js_set
(
js
,
obj
,
"chdir"
,
js_mkfun
(
process_chdir
));
js_set
(
js
,
obj
,
"uptime"
,
js_mkfun
(
process_uptime
));
js_set
(
js
,
obj
,
"cpuUsage"
,
js_mkfun
(
process_cpu_usage
));
js_set
(
js
,
obj
,
"kill"
,
js_mkfun
(
process_kill
));
js_set
(
js
,
obj
,
"abort"
,
js_mkfun
(
process_abort
));
js_set
(
js
,
obj
,
"umask"
,
js_mkfun
(
process_umask
));
js_set
(
js
,
obj
,
"nextTick"
,
js_mkfun
(
process_next_tick
));
js_set
(
js
,
obj
,
"emitWarning"
,
js_mkfun
(
process_emit_warning
));
js_set
(
js
,
obj
,
"dlopen"
,
js_mkfun
(
napi_process_dlopen_js
));
ant_value_t
mem_usage_fn
=
js_heavy_mkfun
(
js
,
process_memory_usage
,
js_mkundef
());
js_set
(
js
,
mem_usage_fn
,
"rss"
,
js_mkfun
(
process_memory_usage_rss
));
js_set
(
js
,
obj
,
"memoryUsage"
,
mem_usage_fn
);
ant_value_t
hrtime_fn
=
js_heavy_mkfun
(
js
,
process_hrtime
,
js_mkundef
());
js_set
(
js
,
hrtime_fn
,
"bigint"
,
js_mkfun
(
process_hrtime_bigint
));
js_set
(
js
,
obj
,
"hrtime"
,
hrtime_fn
);
if
(
include_event_methods
)
{
js_set
(
js
,
obj
,
"on"
,
js_mkfun
(
process_on
));
js_set_exact
(
js
,
obj
,
"addListener"
,
js_get
(
js
,
obj
,
"on"
));
js_set
(
js
,
obj
,
"once"
,
js_mkfun
(
process_once
));
js_set
(
js
,
obj
,
"prependListener"
,
js_mkfun
(
process_prepend_listener
));
js_set
(
js
,
obj
,
"prependOnceListener"
,
js_mkfun
(
process_prepend_once_listener
));
js_set
(
js
,
obj
,
"off"
,
js_mkfun
(
process_off
));
js_set_exact
(
js
,
obj
,
"removeListener"
,
js_get
(
js
,
obj
,
"off"
));
js_set
(
js
,
obj
,
"removeAllListeners"
,
js_mkfun
(
process_remove_all_listeners
));
js_set
(
js
,
obj
,
"emit"
,
js_mkfun
(
process_emit
));
js_set
(
js
,
obj
,
"listenerCount"
,
js_mkfun
(
process_listener_count
));
js_set
(
js
,
obj
,
"listeners"
,
js_mkfun
(
process_listeners
));
js_set
(
js
,
obj
,
"rawListeners"
,
js_mkfun
(
process_raw_listeners
));
js_set
(
js
,
obj
,
"eventNames"
,
js_mkfun
(
process_event_names
));
js_set
(
js
,
obj
,
"setMaxListeners"
,
js_mkfun
(
process_set_max_listeners
));
js_set
(
js
,
obj
,
"getMaxListeners"
,
js_mkfun
(
process_get_max_listeners
));
}
#ifndef _WIN32
js_set
(
js
,
obj
,
"getuid"
,
js_mkfun
(
process_getuid
));
js_set
(
js
,
obj
,
"geteuid"
,
js_mkfun
(
process_geteuid
));
js_set
(
js
,
obj
,
"getgid"
,
js_mkfun
(
process_getgid
));
js_set
(
js
,
obj
,
"getegid"
,
js_mkfun
(
process_getegid
));
js_set
(
js
,
obj
,
"getgroups"
,
js_mkfun
(
process_getgroups
));
js_set
(
js
,
obj
,
"setuid"
,
js_mkfun
(
process_setuid
));
js_set
(
js
,
obj
,
"setgid"
,
js_mkfun
(
process_setgid
));
js_set
(
js
,
obj
,
"seteuid"
,
js_mkfun
(
process_seteuid
));
js_set
(
js
,
obj
,
"setegid"
,
js_mkfun
(
process_setegid
));
js_set
(
js
,
obj
,
"setgroups"
,
js_mkfun
(
process_setgroups
));
js_set
(
js
,
obj
,
"initgroups"
,
js_mkfun
(
process_initgroups
));
#endif
}
ant_value_t
process_library
(
ant_t
*
js
)
{
ant_value_t
process_obj
=
js_get
(
js
,
js_glob
(
js
),
"process"
);
js_set
(
js
,
process_obj
,
"default"
,
process_obj
);
js_set_slot_wb
(
js
,
process_obj
,
SLOT_DEFAULT
,
process_obj
);
return
process_obj
;
}
void
init_process_module
()
{
ant_t
*
js
=
rt
->
js
;
ant_value_t
global
=
js_glob
(
js
);
stdin_state
.
decoder
=
js_mkundef
();
process_start_time
=
uv_hrtime
();
ant_value_t
process_proto
=
js_mkobj
(
js
);
process_set_methods
(
js
,
process_proto
,
true
);
js_set_sym
(
js
,
process_proto
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"process"
,
7
));
ant_value_t
process_obj
=
js_mkobj
(
js
);
ant_value_t
env_obj
=
js_mkobj
(
js
);
js_set_proto_init
(
process_obj
,
process_proto
);
process_set_methods
(
js
,
process_obj
,
false
);
load_dotenv_file
(
js
,
env_obj
);
js_set_keys
(
env_obj
,
env_keys
);
js_set_getter
(
env_obj
,
env_getter
);
js_set_setter
(
env_obj
,
env_setter
);
js_set_deleter
(
env_obj
,
env_deleter
);
js_set
(
js
,
env_obj
,
"toObject"
,
js_mkfun
(
env_to_object
));
js_set
(
js
,
env_obj
,
"toString"
,
js_mkfun
(
env_toString
));
js_set
(
js
,
process_obj
,
"env"
,
env_obj
);
ant_value_t
argv_arr
=
js_mkarr
(
js
);
for
(
int
i
=
0
;
i
<
rt
->
argc
;
i
++
)
{
js_arr_push
(
js
,
argv_arr
,
js_mkstr
(
js
,
rt
->
argv
[
i
],
strlen
(
rt
->
argv
[
i
])));
}
js_set
(
js
,
process_obj
,
"argv"
,
argv_arr
);
js_set
(
js
,
process_obj
,
"execArgv"
,
js_mkarr
(
js
));
js_set
(
js
,
process_obj
,
"argv0"
,
rt
->
argc
>
0
?
js_mkstr
(
js
,
rt
->
argv
[
0
],
strlen
(
rt
->
argv
[
0
]))
:
js_mkstr
(
js
,
"ant"
,
3
));
js_set
(
js
,
process_obj
,
"execPath"
,
rt
->
argc
>
0
?
js_mkstr
(
js
,
rt
->
argv
[
0
],
strlen
(
rt
->
argv
[
0
]))
:
js_mkundef
());
js_set
(
js
,
process_obj
,
"pid"
,
js_mknum
((
double
)
getpid
()));
js_set
(
js
,
process_obj
,
"ppid"
,
js_mknum
((
double
)
getppid
()));
ant_value_t
versions_obj
=
js_mkobj
(
js
);
js_set
(
js
,
versions_obj
,
"ant"
,
js_mkstr
(
js
,
ANT_VERSION
,
strlen
(
ANT_VERSION
)));
char
uv_ver
[
32
];
snprintf
(
uv_ver
,
sizeof
(
uv_ver
),
"%d.%d.%d"
,
UV_VERSION_MAJOR
,
UV_VERSION_MINOR
,
UV_VERSION_PATCH
);
js_set
(
js
,
versions_obj
,
"uv"
,
js_mkstr
(
js
,
uv_ver
,
strlen
(
uv_ver
)));
js_set
(
js
,
process_obj
,
"versions"
,
versions_obj
);
ant_value_t
release_obj
=
js_mkobj
(
js
);
js_set
(
js
,
release_obj
,
"name"
,
js_mkstr
(
js
,
"ant"
,
3
));
js_set
(
js
,
process_obj
,
"release"
,
release_obj
);
// process.platform
#if defined(__APPLE__)
js_set
(
js
,
process_obj
,
"platform"
,
js_mkstr
(
js
,
"darwin"
,
6
));
#elif defined(__linux__)
js_set
(
js
,
process_obj
,
"platform"
,
js_mkstr
(
js
,
"linux"
,
5
));
#elif defined(_WIN32) || defined(_WIN64)
js_set
(
js
,
process_obj
,
"platform"
,
js_mkstr
(
js
,
"win32"
,
5
));
#elif defined(__FreeBSD__)
js_set
(
js
,
process_obj
,
"platform"
,
js_mkstr
(
js
,
"freebsd"
,
7
));
#else
js_set
(
js
,
process_obj
,
"platform"
,
js_mkstr
(
js
,
"unknown"
,
7
));
#endif
// process.arch
#if defined(__x86_64__) || defined(_M_X64)
js_set
(
js
,
process_obj
,
"arch"
,
js_mkstr
(
js
,
"x64"
,
3
));
#elif defined(__i386__) || defined(_M_IX86)
js_set
(
js
,
process_obj
,
"arch"
,
js_mkstr
(
js
,
"ia32"
,
4
));
#elif defined(__aarch64__) || defined(_M_ARM64)
js_set
(
js
,
process_obj
,
"arch"
,
js_mkstr
(
js
,
"arm64"
,
5
));
#elif defined(__arm__) || defined(_M_ARM)
js_set
(
js
,
process_obj
,
"arch"
,
js_mkstr
(
js
,
"arm"
,
3
));
#else
js_set
(
js
,
process_obj
,
"arch"
,
js_mkstr
(
js
,
"unknown"
,
7
));
#endif
ant_value_t
stdin_proto
=
js_mkobj
(
js
);
js_set
(
js
,
stdin_proto
,
"setRawMode"
,
js_mkfun
(
js_stdin_set_raw_mode
));
js_set
(
js
,
stdin_proto
,
"setEncoding"
,
js_mkfun
(
js_stdin_set_encoding
));
js_set
(
js
,
stdin_proto
,
"resume"
,
js_mkfun
(
js_stdin_resume
));
js_set
(
js
,
stdin_proto
,
"pause"
,
js_mkfun
(
js_stdin_pause
));
js_set
(
js
,
stdin_proto
,
"on"
,
js_mkfun
(
js_stdin_on
));
js_set
(
js
,
stdin_proto
,
"off"
,
js_mkfun
(
js_stdin_remove_listener
));
js_set_exact
(
js
,
stdin_proto
,
"removeListener"
,
js_get
(
js
,
stdin_proto
,
"off"
));
js_set
(
js
,
stdin_proto
,
"removeAllListeners"
,
js_mkfun
(
js_stdin_remove_all_listeners
));
js_set_sym
(
js
,
stdin_proto
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"ReadStream"
,
10
));
ant_value_t
stdin_obj
=
js_mkobj
(
js
);
js_set_proto_init
(
stdin_obj
,
stdin_proto
);
js_set
(
js
,
stdin_obj
,
"isTTY"
,
js_bool
(
stdin_is_tty
()));
js_set
(
js
,
stdin_obj
,
"encoding"
,
js_mkundef
());
js_set
(
js
,
process_obj
,
"stdin"
,
stdin_obj
);
ant_value_t
stdout_proto
=
js_mkobj
(
js
);
js_set
(
js
,
stdout_proto
,
"write"
,
js_mkfun
(
js_stdout_write
));
js_set
(
js
,
stdout_proto
,
"on"
,
js_mkfun
(
js_stdout_on
));
js_set
(
js
,
stdout_proto
,
"once"
,
js_mkfun
(
js_stdout_once
));
js_set
(
js
,
stdout_proto
,
"off"
,
js_mkfun
(
js_stdout_remove_listener
));
js_set_exact
(
js
,
stdout_proto
,
"removeListener"
,
js_get
(
js
,
stdout_proto
,
"off"
));
js_set
(
js
,
stdout_proto
,
"removeAllListeners"
,
js_mkfun
(
js_stdout_remove_all_listeners
));
js_set
(
js
,
stdout_proto
,
"getWindowSize"
,
js_mkfun
(
js_stdout_get_window_size
));
js_set_sym
(
js
,
stdout_proto
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"WriteStream"
,
11
));
ant_value_t
stdout_obj
=
js_mkobj
(
js
);
js_set_proto_init
(
stdout_obj
,
stdout_proto
);
js_set
(
js
,
stdout_obj
,
"isTTY"
,
js_bool
(
stdout_is_tty
()));
js_set_getter_desc
(
js
,
stdout_obj
,
"rows"
,
4
,
js_mkfun
(
js_stdout_rows_getter
),
JS_DESC_E
|
JS_DESC_C
);
js_set_getter_desc
(
js
,
stdout_obj
,
"columns"
,
7
,
js_mkfun
(
js_stdout_columns_getter
),
JS_DESC_E
|
JS_DESC_C
);
js_set
(
js
,
process_obj
,
"stdout"
,
stdout_obj
);
ant_value_t
stderr_proto
=
js_mkobj
(
js
);
js_set
(
js
,
stderr_proto
,
"write"
,
js_mkfun
(
js_stderr_write
));
js_set
(
js
,
stderr_proto
,
"on"
,
js_mkfun
(
js_stderr_on
));
js_set
(
js
,
stderr_proto
,
"once"
,
js_mkfun
(
js_stderr_once
));
js_set
(
js
,
stderr_proto
,
"off"
,
js_mkfun
(
js_stderr_remove_listener
));
js_set_exact
(
js
,
stderr_proto
,
"removeListener"
,
js_get
(
js
,
stderr_proto
,
"off"
));
js_set
(
js
,
stderr_proto
,
"removeAllListeners"
,
js_mkfun
(
js_stderr_remove_all_listeners
));
js_set_sym
(
js
,
stderr_proto
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"WriteStream"
,
11
));
ant_value_t
stderr_obj
=
js_mkobj
(
js
);
js_set_proto_init
(
stderr_obj
,
stderr_proto
);
js_set
(
js
,
stderr_obj
,
"isTTY"
,
js_bool
(
stderr_is_tty
()));
js_set
(
js
,
process_obj
,
"stderr"
,
stderr_obj
);
js_set
(
js
,
global
,
"process"
,
process_obj
);
}
bool
has_active_stdin
(
void
)
{
return
stdin_state
.
reading
;
}
void
gc_mark_process
(
ant_t
*
js
,
gc_mark_fn
mark
)
{
ProcessEventType
*
tables
[]
=
{
process_events
,
stdin_events
,
stdout_events
,
stderr_events
};
for
(
int
t
=
0
;
t
<
4
;
t
++
)
{
ProcessEventType
*
evt
,
*
tmp
;
HASH_ITER
(
hh
,
tables
[
t
],
evt
,
tmp
)
for
(
int
i
=
0
;
i
<
evt
->
listener_count
;
i
++
)
mark
(
js
,
evt
->
listeners
[
i
].
listener
);
}
if
(
is_object_type
(
stdin_state
.
decoder
))
mark
(
js
,
stdin_state
.
decoder
);
}
void
process_enable_keypress_events
(
void
)
{
stdin_state
.
keypress_enabled
=
true
;
stdin_state
.
escape_state
=
0
;
stdin_state
.
escape_len
=
0
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sat, May 2, 4:57 AM (1 d, 21 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
541787
Default Alt Text
process.c (61 KB)
Attached To
Mode
rANT Ant
Attached
Detach File
Event Timeline
Log In to Comment