1use core::{
21 ffi::{VaList as va_list, c_char, c_int},
22 ptr,
23};
24
25use crate::{
26 header::{
27 stdio::{self, FILE, fprintf, fputc, fputs, vfprintf},
28 stdlib::exit,
29 string::strerror,
30 },
31 platform::{self, ERRNO},
32};
33
34type ExitCallback = Option<unsafe extern "C" fn(c_int)>;
36static mut ON_EXIT: ExitCallback = None;
37
38static mut ERROR_SINK: *mut FILE = ptr::null_mut();
40
41#[unsafe(no_mangle)]
43pub unsafe extern "C" fn err_set_file(fp: *mut FILE) {
44 if fp.is_null() {
45 unsafe {
46 ERROR_SINK = stdio::stderr;
47 }
48 } else {
49 unsafe {
50 ERROR_SINK = fp;
51 }
52 }
53}
54
55#[unsafe(no_mangle)]
57pub unsafe extern "C" fn err_set_exit(ef: ExitCallback) {
58 unsafe {
59 ON_EXIT = ef;
60 }
61}
62
63#[unsafe(no_mangle)]
70pub unsafe extern "C" fn err(eval: c_int, fmt: *const c_char, va_list: ...) -> ! {
71 let code = Some(ERRNO.get());
72 unsafe { err_exit(eval, code, fmt, va_list) }
73}
74
75#[unsafe(no_mangle)]
82pub unsafe extern "C" fn errc(eval: c_int, code: c_int, fmt: *const c_char, va_list: ...) -> ! {
83 unsafe { err_exit(eval, Some(code), fmt, va_list) }
84}
85
86#[unsafe(no_mangle)]
93pub unsafe extern "C" fn errx(eval: c_int, fmt: *const c_char, va_list: ...) -> ! {
94 unsafe { err_exit(eval, None, fmt, va_list) }
95}
96
97#[unsafe(no_mangle)]
101pub unsafe extern "C" fn warn(fmt: *const c_char, va_list: ...) {
102 let code = Some(ERRNO.get());
103 unsafe {
104 display_message(code, fmt, va_list);
105 }
106}
107
108#[unsafe(no_mangle)]
112pub unsafe extern "C" fn warnc(code: c_int, fmt: *const c_char, va_list: ...) {
113 unsafe {
114 display_message(Some(code), fmt, va_list);
115 }
116}
117
118#[unsafe(no_mangle)]
122pub unsafe extern "C" fn warnx(fmt: *const c_char, va_list: ...) {
123 unsafe {
124 display_message(None, fmt, va_list);
125 }
126}
127
128#[unsafe(no_mangle)]
130pub unsafe extern "C" fn verr(eval: c_int, fmt: *const c_char, args: va_list) -> ! {
131 let code = Some(ERRNO.get());
132 unsafe {
133 err_exit(eval, code, fmt, args);
134 }
135}
136
137#[unsafe(no_mangle)]
139pub unsafe extern "C" fn verrc(eval: c_int, code: c_int, fmt: *const c_char, args: va_list) -> ! {
140 unsafe { err_exit(eval, Some(code), fmt, args) }
141}
142
143#[unsafe(no_mangle)]
145pub unsafe extern "C" fn verrx(eval: c_int, fmt: *const c_char, args: va_list) -> ! {
146 unsafe { err_exit(eval, None, fmt, args) }
147}
148
149#[unsafe(no_mangle)]
151pub unsafe extern "C" fn vwarn(fmt: *const c_char, args: va_list) {
152 let code = Some(ERRNO.get());
153 unsafe {
154 display_message(code, fmt, args);
155 }
156}
157
158#[unsafe(no_mangle)]
160pub unsafe extern "C" fn vwarnc(code: c_int, fmt: *const c_char, args: va_list) {
161 unsafe {
162 display_message(Some(code), fmt, args);
163 }
164}
165
166#[unsafe(no_mangle)]
168pub unsafe extern "C" fn vwarnx(fmt: *const c_char, args: va_list) {
169 unsafe {
170 display_message(None, fmt, args);
171 }
172}
173
174unsafe fn display_message(code: Option<c_int>, fmt: *const c_char, args: va_list) {
176 if unsafe { ERROR_SINK.is_null() } {
180 unsafe {
181 ERROR_SINK = stdio::stderr;
182 }
183 }
184 let sink = unsafe { ERROR_SINK };
185
186 unsafe {
191 fprintf(
192 sink,
193 c"%s".as_ptr(),
194 platform::program_invocation_short_name,
195 );
196 }
197
198 if !fmt.is_null() {
200 unsafe {
201 fputs(c": ".as_ptr(), sink);
202 vfprintf(sink, fmt, args);
203 }
204 }
205
206 if let Some(code) = code {
208 unsafe {
209 let message = strerror(code);
210 fprintf(sink, c": %s".as_ptr(), message);
211 }
212 }
213
214 unsafe {
216 fputc(b'\n'.into(), sink);
217 }
218}
219
220unsafe fn err_exit(eval: c_int, code: Option<c_int>, fmt: *const c_char, args: va_list) -> ! {
222 unsafe {
223 display_message(code, fmt, args);
224 }
225
226 if let Some(callback) = unsafe { ON_EXIT } {
227 unsafe {
229 callback(code.unwrap_or_else(|| ERRNO.get()));
230 }
231 }
232
233 unsafe {
234 exit(eval);
235 }
236}