1use std::collections::HashMap;
27
28mod prototypes;
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
32pub enum StdHeader {
33 Assert, Ctype, Errno, Float, Limits, Locale, Math, Setjmp, Signal, Stdarg, Stdbool, Stddef, Stdint, Stdio, Stdlib, String, Time, Unistd, Fcntl, Dirent, SysTypes, SysStat, SysMman, Wchar, }
59
60impl StdHeader {
61 pub fn from_filename(filename: &str) -> Option<Self> {
71 match filename {
72 "assert.h" => Some(Self::Assert),
73 "ctype.h" => Some(Self::Ctype),
74 "errno.h" => Some(Self::Errno),
75 "float.h" => Some(Self::Float),
76 "limits.h" => Some(Self::Limits),
77 "locale.h" => Some(Self::Locale),
78 "math.h" => Some(Self::Math),
79 "setjmp.h" => Some(Self::Setjmp),
80 "signal.h" => Some(Self::Signal),
81 "stdarg.h" => Some(Self::Stdarg),
82 "stdbool.h" => Some(Self::Stdbool),
83 "stddef.h" => Some(Self::Stddef),
84 "stdint.h" => Some(Self::Stdint),
85 "stdio.h" => Some(Self::Stdio),
86 "stdlib.h" => Some(Self::Stdlib),
87 "string.h" => Some(Self::String),
88 "time.h" => Some(Self::Time),
89 "unistd.h" => Some(Self::Unistd),
91 "fcntl.h" => Some(Self::Fcntl),
92 "dirent.h" => Some(Self::Dirent),
93 "sys/types.h" => Some(Self::SysTypes),
94 "sys/stat.h" => Some(Self::SysStat),
95 "sys/mman.h" => Some(Self::SysMman),
96 "wchar.h" => Some(Self::Wchar),
97 _ => None,
98 }
99 }
100}
101
102#[derive(Debug, Clone, PartialEq, Eq)]
104pub struct Parameter {
105 pub name: String,
106 pub type_str: String,
107}
108
109impl Parameter {
110 pub fn new(name: impl Into<String>, type_str: impl Into<String>) -> Self {
111 Self { name: name.into(), type_str: type_str.into() }
112 }
113}
114
115#[derive(Debug, Clone, PartialEq, Eq)]
117pub struct FunctionProto {
118 pub name: String,
119 pub return_type: String,
120 pub parameters: Vec<Parameter>,
121 pub is_variadic: bool,
122 pub header: StdHeader,
123 pub c99_section: String,
124}
125
126impl FunctionProto {
127 pub fn to_c_declaration(&self) -> String {
129 let params = if self.parameters.is_empty() {
130 "void".to_string()
131 } else {
132 let mut p = self
133 .parameters
134 .iter()
135 .map(|param| format!("{} {}", param.type_str, param.name))
136 .collect::<Vec<_>>()
137 .join(", ");
138
139 if self.is_variadic {
140 p.push_str(", ...");
141 }
142
143 p
144 };
145
146 format!("{} {}({});", self.return_type, self.name, params)
147 }
148}
149
150pub struct StdlibPrototypes {
162 functions: HashMap<String, FunctionProto>,
163}
164
165impl StdlibPrototypes {
166 pub fn new() -> Self {
180 Self::build_all_prototypes()
181 }
182
183 fn build_all_prototypes() -> Self {
185 let mut functions = HashMap::new();
186 Self::init_stdlib(&mut functions);
187 Self::init_stdio(&mut functions);
188 Self::init_string(&mut functions);
189 Self::init_ctype(&mut functions);
190 Self::init_time(&mut functions);
191 Self::init_math(&mut functions);
192 Self::init_posix_unistd(&mut functions);
193 Self::init_posix_dirent(&mut functions);
194 Self { functions }
195 }
196
197 pub fn get_prototype(&self, name: &str) -> Option<&FunctionProto> {
199 self.functions.get(name)
200 }
201
202 pub fn inject_prototypes_for_header(&self, header: StdHeader) -> String {
216 let mut result = String::new();
217
218 result.push_str(&format!("// Built-in prototypes for {:?} (ISO C99 §7)\n", header));
220 result.push_str("typedef unsigned long size_t;\n");
221 result.push_str("typedef long ssize_t;\n");
222 result.push_str("typedef long ptrdiff_t;\n");
223 result.push_str("#define NULL 0\n");
225
226 match header {
228 StdHeader::Stdio => {
229 result.push_str("struct _IO_FILE;\n");
230 result.push_str("typedef struct _IO_FILE FILE;\n");
231 result.push_str("extern FILE* stdin;\n");
233 result.push_str("extern FILE* stdout;\n");
234 result.push_str("extern FILE* stderr;\n");
235 result.push_str("#define EOF (-1)\n");
237 result.push_str("#define SEEK_SET 0\n");
238 result.push_str("#define SEEK_CUR 1\n");
239 result.push_str("#define SEEK_END 2\n");
240 result.push_str("#define BUFSIZ 8192\n");
241 result.push_str("#define L_tmpnam 20\n");
242 result.push_str("#define _IONBF 2\n");
243 result.push_str("#define _IOLBF 1\n");
244 result.push_str("#define _IOFBF 0\n");
245 }
246 StdHeader::Errno => {
247 result.push_str("extern int errno;\n");
248 result.push_str("#define EACCES 13\n");
249 result.push_str("#define ENOENT 2\n");
250 result.push_str("#define EINVAL 22\n");
251 result.push_str("#define ENOMEM 12\n");
252 result.push_str("#define ERANGE 34\n");
253 }
254 StdHeader::Time => {
255 result.push_str("typedef long time_t;\n");
256 result.push_str("typedef long clock_t;\n");
257 result.push_str("struct tm;\n");
258 result.push_str("#define CLOCKS_PER_SEC 1000000\n");
259 }
260 StdHeader::Stdarg => {
261 result.push_str("typedef void* va_list;\n");
263 result.push_str("#define va_start(ap, last) ((void)0)\n");
264 result.push_str("#define va_end(ap) ((void)0)\n");
265 result.push_str("#define va_arg(ap, type) (*(type*)0)\n");
266 }
267 StdHeader::Stdbool => {
268 result.push_str("typedef _Bool bool;\n");
269 result.push_str("#define true 1\n");
270 result.push_str("#define false 0\n");
271 }
272 StdHeader::Stdint => {
273 result.push_str("typedef signed char int8_t;\n");
274 result.push_str("typedef short int16_t;\n");
275 result.push_str("typedef int int32_t;\n");
276 result.push_str("typedef long long int64_t;\n");
277 result.push_str("typedef unsigned char uint8_t;\n");
278 result.push_str("typedef unsigned short uint16_t;\n");
279 result.push_str("typedef unsigned int uint32_t;\n");
280 result.push_str("typedef unsigned long long uint64_t;\n");
281 result.push_str("typedef long intptr_t;\n");
282 result.push_str("typedef unsigned long uintptr_t;\n");
283 }
284 StdHeader::Unistd => {
285 result.push_str("typedef int pid_t;\n");
287 result.push_str("typedef long off_t;\n");
288 result.push_str("typedef unsigned int uid_t;\n");
289 result.push_str("typedef unsigned int gid_t;\n");
290 result.push_str("#define STDIN_FILENO 0\n");
291 result.push_str("#define STDOUT_FILENO 1\n");
292 result.push_str("#define STDERR_FILENO 2\n");
293 result.push_str("#define F_OK 0\n");
295 result.push_str("#define R_OK 4\n");
296 result.push_str("#define W_OK 2\n");
297 result.push_str("#define X_OK 1\n");
298 result.push_str("#define _SC_OPEN_MAX 4\n");
300 result.push_str("#define _SC_PAGESIZE 30\n");
301 }
302 StdHeader::Fcntl => {
303 result.push_str("#define O_RDONLY 0\n");
305 result.push_str("#define O_WRONLY 1\n");
306 result.push_str("#define O_RDWR 2\n");
307 result.push_str("#define O_CREAT 0100\n");
308 result.push_str("#define O_TRUNC 01000\n");
309 result.push_str("#define O_APPEND 02000\n");
310 result.push_str("#define O_NONBLOCK 04000\n");
311 result.push_str("#define LOCK_SH 1\n");
313 result.push_str("#define LOCK_EX 2\n");
314 result.push_str("#define LOCK_UN 8\n");
315 }
316 StdHeader::Dirent => {
317 result.push_str("struct dirent { char d_name[256]; };\n");
318 result.push_str("typedef struct __dirstream DIR;\n");
319 }
320 StdHeader::SysTypes => {
321 result.push_str("typedef int pid_t;\n");
322 result.push_str("typedef long off_t;\n");
323 result.push_str("typedef unsigned int mode_t;\n");
324 result.push_str("typedef long ssize_t;\n");
325 }
326 StdHeader::SysStat => {
327 result.push_str("struct stat { long st_size; int st_mode; };\n");
328 result.push_str("#define S_ISREG(m) (((m) & 0170000) == 0100000)\n");
329 result.push_str("#define S_ISDIR(m) (((m) & 0170000) == 0040000)\n");
330 }
331 StdHeader::SysMman => {
332 result.push_str("#define PROT_NONE 0\n");
334 result.push_str("#define PROT_READ 1\n");
335 result.push_str("#define PROT_WRITE 2\n");
336 result.push_str("#define PROT_EXEC 4\n");
337 result.push_str("#define MAP_SHARED 1\n");
339 result.push_str("#define MAP_PRIVATE 2\n");
340 result.push_str("#define MAP_ANONYMOUS 0x20\n");
341 result.push_str("#define MAP_FAILED ((void*)-1)\n");
342 }
343 StdHeader::Wchar => {
344 result.push_str("typedef int wchar_t;\n");
345 result.push_str("typedef int wint_t;\n");
346 result.push_str("#define WEOF (-1)\n");
347 }
348 StdHeader::Signal => {
349 result.push_str("typedef void (*sighandler_t)(int);\n");
350 result.push_str("#define SIGINT 2\n");
351 result.push_str("#define SIGTERM 15\n");
352 }
353 StdHeader::Limits => {
354 result.push_str("#define CHAR_BIT 8\n");
355 result.push_str("#define CHAR_MIN (-128)\n");
356 result.push_str("#define CHAR_MAX 127\n");
357 result.push_str("#define SHRT_MIN (-32768)\n");
358 result.push_str("#define SHRT_MAX 32767\n");
359 result.push_str("#define INT_MIN (-2147483647-1)\n");
360 result.push_str("#define INT_MAX 2147483647\n");
361 result.push_str("#define UINT_MAX 4294967295U\n");
362 result.push_str("#define LONG_MIN (-9223372036854775807L-1)\n");
363 result.push_str("#define LONG_MAX 9223372036854775807L\n");
364 result.push_str("#define PATH_MAX 4096\n");
365 }
366 StdHeader::Ctype => {
367 }
370 StdHeader::Math => {
371 result.push_str("#define M_PI 3.14159265358979323846\n");
373 result.push_str("#define M_E 2.71828182845904523536\n");
374 result.push_str("#define INFINITY (1.0/0.0)\n");
375 result.push_str("#define NAN (0.0/0.0)\n");
376 }
377 _ => {}
378 }
379
380 result.push('\n');
381
382 let mut protos: Vec<_> = self
387 .functions
388 .values()
389 .filter(|p| p.header == header)
390 .filter(|p| {
391 !p.parameters.iter().any(|param| param.type_str.contains("(*"))
393 })
394 .collect();
395 protos.sort_by_key(|p| &p.name);
396
397 for proto in protos {
398 result.push_str(&proto.to_c_declaration());
399 result.push('\n');
400 }
401
402 result
403 }
404
405 pub fn inject_all_prototypes(&self) -> String {
410 let mut result = String::new();
411
412 result.push_str("// Built-in stdlib prototypes (ISO C99 §7)\n");
414 result.push_str("typedef unsigned long size_t;\n");
415 result.push_str("typedef long ssize_t;\n");
416 result.push_str("typedef long ptrdiff_t;\n");
417 result.push_str("#define NULL 0\n");
419 result.push_str("struct _IO_FILE;\n");
420 result.push_str("typedef struct _IO_FILE FILE;\n");
421 result.push_str("extern FILE* stdin;\n");
423 result.push_str("extern FILE* stdout;\n");
424 result.push_str("extern FILE* stderr;\n");
425 result.push_str("#define EOF (-1)\n");
426 result.push_str("#define SEEK_SET 0\n");
427 result.push_str("#define SEEK_CUR 1\n");
428 result.push_str("#define SEEK_END 2\n");
429 result.push_str("typedef int pid_t;\n");
431 result.push_str("typedef long off_t;\n");
432 result.push_str("typedef long time_t;\n");
433 result.push_str("typedef long clock_t;\n");
434 result.push_str("typedef int wchar_t;\n");
435 result.push_str("extern int errno;\n");
436 result.push_str("#define CLOCKS_PER_SEC 1000000\n");
438 result.push_str("#define PATH_MAX 4096\n");
439 result.push('\n');
440
441 let mut protos: Vec<_> = self.functions.values().collect();
443 protos.sort_by_key(|p| &p.name);
444
445 for proto in protos {
446 result.push_str(&proto.to_c_declaration());
447 result.push('\n');
448 }
449
450 result
451 }
452
453 pub fn len(&self) -> usize {
455 self.functions.len()
456 }
457
458 pub fn is_empty(&self) -> bool {
460 self.functions.is_empty()
461 }
462}
463
464impl Default for StdlibPrototypes {
465 fn default() -> Self {
466 Self::new()
467 }
468}
469
470#[cfg(test)]
471#[path = "inject_prototype_tests.rs"]
472mod inject_prototype_tests;
473
474#[cfg(test)]
475mod tests {
476 use super::*;
477
478 #[test]
479 fn test_function_proto_to_c_declaration() {
480 let proto = FunctionProto {
481 name: "malloc".to_string(),
482 return_type: "void*".to_string(),
483 parameters: vec![Parameter::new("size", "size_t")],
484 is_variadic: false,
485 header: StdHeader::Stdlib,
486 c99_section: "§7.22.3.4".to_string(),
487 };
488
489 assert_eq!(proto.to_c_declaration(), "void* malloc(size_t size);");
490 }
491
492 #[test]
493 fn test_variadic_function_proto() {
494 let proto = FunctionProto {
495 name: "printf".to_string(),
496 return_type: "int".to_string(),
497 parameters: vec![Parameter::new("format", "const char*")],
498 is_variadic: true,
499 header: StdHeader::Stdio,
500 c99_section: "§7.21.6.1".to_string(),
501 };
502
503 assert_eq!(proto.to_c_declaration(), "int printf(const char* format, ...);");
504 }
505
506 #[test]
507 fn test_no_param_function_proto() {
508 let proto = FunctionProto {
509 name: "rand".to_string(),
510 return_type: "int".to_string(),
511 parameters: vec![],
512 is_variadic: false,
513 header: StdHeader::Stdlib,
514 c99_section: "§7.22.2.1".to_string(),
515 };
516
517 assert_eq!(proto.to_c_declaration(), "int rand(void);");
518 }
519
520 #[test]
525 fn test_inject_header_common_preamble_present_for_all_headers() {
526 let stdlib = StdlibPrototypes::new();
527 let headers = [
528 StdHeader::Stdio,
529 StdHeader::Errno,
530 StdHeader::Time,
531 StdHeader::Stdarg,
532 StdHeader::Stdbool,
533 StdHeader::Stdint,
534 StdHeader::Unistd,
535 StdHeader::Fcntl,
536 StdHeader::Dirent,
537 StdHeader::SysTypes,
538 StdHeader::SysStat,
539 StdHeader::SysMman,
540 StdHeader::Wchar,
541 StdHeader::Signal,
542 StdHeader::Limits,
543 StdHeader::Ctype,
544 StdHeader::Math,
545 StdHeader::Assert,
546 StdHeader::Float,
547 StdHeader::Locale,
548 StdHeader::Setjmp,
549 StdHeader::Stddef,
550 StdHeader::Stdlib,
551 StdHeader::String,
552 ];
553 for header in &headers {
554 let result = stdlib.inject_prototypes_for_header(*header);
555 assert!(
556 result.contains("typedef unsigned long size_t;"),
557 "{:?} missing size_t",
558 header
559 );
560 assert!(result.contains("typedef long ssize_t;"), "{:?} missing ssize_t", header);
561 assert!(result.contains("typedef long ptrdiff_t;"), "{:?} missing ptrdiff_t", header);
562 assert!(result.contains("#define NULL 0"), "{:?} missing NULL", header);
563 assert!(
564 result.contains("// Built-in prototypes for"),
565 "{:?} missing comment header",
566 header
567 );
568 }
569 }
570
571 #[test]
576 fn test_inject_header_stdio_type_definitions() {
577 let stdlib = StdlibPrototypes::new();
578 let result = stdlib.inject_prototypes_for_header(StdHeader::Stdio);
579 assert!(result.contains("struct _IO_FILE;"));
580 assert!(result.contains("typedef struct _IO_FILE FILE;"));
581 assert!(result.contains("extern FILE* stdin;"));
582 assert!(result.contains("extern FILE* stdout;"));
583 assert!(result.contains("extern FILE* stderr;"));
584 }
585
586 #[test]
587 fn test_inject_header_stdio_macros() {
588 let stdlib = StdlibPrototypes::new();
589 let result = stdlib.inject_prototypes_for_header(StdHeader::Stdio);
590 assert!(result.contains("#define EOF (-1)"));
591 assert!(result.contains("#define SEEK_SET 0"));
592 assert!(result.contains("#define SEEK_CUR 1"));
593 assert!(result.contains("#define SEEK_END 2"));
594 assert!(result.contains("#define BUFSIZ 8192"));
595 assert!(result.contains("#define L_tmpnam 20"));
596 assert!(result.contains("#define _IONBF 2"));
597 assert!(result.contains("#define _IOLBF 1"));
598 assert!(result.contains("#define _IOFBF 0"));
599 }
600
601 #[test]
602 fn test_inject_header_stdio_functions() {
603 let stdlib = StdlibPrototypes::new();
604 let result = stdlib.inject_prototypes_for_header(StdHeader::Stdio);
605 assert!(result.contains("int printf(const char* format, ...);"));
607 assert!(result.contains("int fprintf(FILE* stream, const char* format, ...);"));
608 assert!(result.contains("int sprintf(char* str, const char* format, ...);"));
609 assert!(result.contains("int snprintf(char* str, size_t size, const char* format, ...);"));
610 assert!(result.contains("int scanf(const char* format, ...);"));
612 assert!(result.contains("int fscanf(FILE* stream, const char* format, ...);"));
613 assert!(result.contains("int sscanf(const char* str, const char* format, ...);"));
614 assert!(result.contains("FILE* fopen("));
616 assert!(result.contains("int fclose(FILE* stream);"));
617 assert!(result.contains("size_t fread("));
618 assert!(result.contains("size_t fwrite("));
619 assert!(result.contains("int fseek("));
620 assert!(result.contains("long ftell(FILE* stream);"));
621 assert!(result.contains("void rewind(FILE* stream);"));
622 assert!(result.contains("int getchar(void);"));
624 assert!(result.contains("int putchar(int c);"));
625 assert!(result.contains("int fgetc(FILE* stream);"));
626 assert!(result.contains("int fputc(int c, FILE* stream);"));
627 assert!(result.contains("char* fgets("));
628 assert!(result.contains("int fputs("));
629 assert!(result.contains("int puts(const char* s);"));
630 }
631
632 #[test]
633 fn test_inject_header_stdio_does_not_contain_stdlib_functions() {
634 let stdlib = StdlibPrototypes::new();
635 let result = stdlib.inject_prototypes_for_header(StdHeader::Stdio);
636 assert!(!result.contains("void* malloc("));
638 assert!(!result.contains("void free("));
639 }
640
641 #[test]
646 fn test_inject_header_errno_definitions() {
647 let stdlib = StdlibPrototypes::new();
648 let result = stdlib.inject_prototypes_for_header(StdHeader::Errno);
649 assert!(result.contains("extern int errno;"));
650 assert!(result.contains("#define EACCES 13"));
651 assert!(result.contains("#define ENOENT 2"));
652 assert!(result.contains("#define EINVAL 22"));
653 assert!(result.contains("#define ENOMEM 12"));
654 assert!(result.contains("#define ERANGE 34"));
655 }
656
657 #[test]
658 fn test_inject_header_errno_no_functions() {
659 let stdlib = StdlibPrototypes::new();
660 let result = stdlib.inject_prototypes_for_header(StdHeader::Errno);
661 assert!(!result.contains("int printf("));
663 assert!(!result.contains("void* malloc("));
664 }
665
666 #[test]
671 fn test_inject_header_time_type_definitions() {
672 let stdlib = StdlibPrototypes::new();
673 let result = stdlib.inject_prototypes_for_header(StdHeader::Time);
674 assert!(result.contains("typedef long time_t;"));
675 assert!(result.contains("typedef long clock_t;"));
676 assert!(result.contains("struct tm;"));
677 assert!(result.contains("#define CLOCKS_PER_SEC 1000000"));
678 }
679
680 #[test]
681 fn test_inject_header_time_functions() {
682 let stdlib = StdlibPrototypes::new();
683 let result = stdlib.inject_prototypes_for_header(StdHeader::Time);
684 assert!(result.contains("clock_t clock(void);"));
685 assert!(result.contains("time_t time(time_t* timer);"));
686 }
687
688 #[test]
693 fn test_inject_header_stdarg_definitions() {
694 let stdlib = StdlibPrototypes::new();
695 let result = stdlib.inject_prototypes_for_header(StdHeader::Stdarg);
696 assert!(result.contains("typedef void* va_list;"));
697 assert!(result.contains("#define va_start(ap, last) ((void)0)"));
698 assert!(result.contains("#define va_end(ap) ((void)0)"));
699 assert!(result.contains("#define va_arg(ap, type) (*(type*)0)"));
700 }
701
702 #[test]
707 fn test_inject_header_stdbool_definitions() {
708 let stdlib = StdlibPrototypes::new();
709 let result = stdlib.inject_prototypes_for_header(StdHeader::Stdbool);
710 assert!(result.contains("typedef _Bool bool;"));
711 assert!(result.contains("#define true 1"));
712 assert!(result.contains("#define false 0"));
713 }
714
715 #[test]
720 fn test_inject_header_stdint_type_definitions() {
721 let stdlib = StdlibPrototypes::new();
722 let result = stdlib.inject_prototypes_for_header(StdHeader::Stdint);
723 assert!(result.contains("typedef signed char int8_t;"));
724 assert!(result.contains("typedef short int16_t;"));
725 assert!(result.contains("typedef int int32_t;"));
726 assert!(result.contains("typedef long long int64_t;"));
727 assert!(result.contains("typedef unsigned char uint8_t;"));
728 assert!(result.contains("typedef unsigned short uint16_t;"));
729 assert!(result.contains("typedef unsigned int uint32_t;"));
730 assert!(result.contains("typedef unsigned long long uint64_t;"));
731 assert!(result.contains("typedef long intptr_t;"));
732 assert!(result.contains("typedef unsigned long uintptr_t;"));
733 }
734
735 #[test]
740 fn test_inject_header_unistd_type_definitions() {
741 let stdlib = StdlibPrototypes::new();
742 let result = stdlib.inject_prototypes_for_header(StdHeader::Unistd);
743 assert!(result.contains("typedef int pid_t;"));
744 assert!(result.contains("typedef long off_t;"));
745 assert!(result.contains("typedef unsigned int uid_t;"));
746 assert!(result.contains("typedef unsigned int gid_t;"));
747 }
748
749 #[test]
750 fn test_inject_header_unistd_macros() {
751 let stdlib = StdlibPrototypes::new();
752 let result = stdlib.inject_prototypes_for_header(StdHeader::Unistd);
753 assert!(result.contains("#define STDIN_FILENO 0"));
754 assert!(result.contains("#define STDOUT_FILENO 1"));
755 assert!(result.contains("#define STDERR_FILENO 2"));
756 assert!(result.contains("#define F_OK 0"));
757 assert!(result.contains("#define R_OK 4"));
758 assert!(result.contains("#define W_OK 2"));
759 assert!(result.contains("#define X_OK 1"));
760 assert!(result.contains("#define _SC_OPEN_MAX 4"));
761 assert!(result.contains("#define _SC_PAGESIZE 30"));
762 }
763
764 #[test]
765 fn test_inject_header_unistd_functions() {
766 let stdlib = StdlibPrototypes::new();
767 let result = stdlib.inject_prototypes_for_header(StdHeader::Unistd);
768 assert!(result.contains("int pipe(int* pipefd);"));
769 assert!(result.contains("pid_t fork(void);"));
770 assert!(result.contains("ssize_t read(int fd, void* buf, size_t count);"));
771 assert!(result.contains("ssize_t write(int fd, const void* buf, size_t count);"));
772 assert!(result.contains("int close(int fd);"));
773 assert!(result.contains("off_t lseek(int fd, off_t offset, int whence);"));
774 assert!(result.contains("int dup(int oldfd);"));
775 assert!(result.contains("int dup2(int oldfd, int newfd);"));
776 }
777
778 #[test]
783 fn test_inject_header_fcntl_macros() {
784 let stdlib = StdlibPrototypes::new();
785 let result = stdlib.inject_prototypes_for_header(StdHeader::Fcntl);
786 assert!(result.contains("#define O_RDONLY 0"));
787 assert!(result.contains("#define O_WRONLY 1"));
788 assert!(result.contains("#define O_RDWR 2"));
789 assert!(result.contains("#define O_CREAT 0100"));
790 assert!(result.contains("#define O_TRUNC 01000"));
791 assert!(result.contains("#define O_APPEND 02000"));
792 assert!(result.contains("#define O_NONBLOCK 04000"));
793 assert!(result.contains("#define LOCK_SH 1"));
794 assert!(result.contains("#define LOCK_EX 2"));
795 assert!(result.contains("#define LOCK_UN 8"));
796 }
797
798 #[test]
799 fn test_inject_header_fcntl_functions() {
800 let stdlib = StdlibPrototypes::new();
801 let result = stdlib.inject_prototypes_for_header(StdHeader::Fcntl);
802 assert!(result.contains("int open(const char* pathname, int flags, ...);"));
803 }
804
805 #[test]
810 fn test_inject_header_dirent_type_definitions() {
811 let stdlib = StdlibPrototypes::new();
812 let result = stdlib.inject_prototypes_for_header(StdHeader::Dirent);
813 assert!(result.contains("struct dirent { char d_name[256]; };"));
814 assert!(result.contains("typedef struct __dirstream DIR;"));
815 }
816
817 #[test]
818 fn test_inject_header_dirent_functions() {
819 let stdlib = StdlibPrototypes::new();
820 let result = stdlib.inject_prototypes_for_header(StdHeader::Dirent);
821 assert!(result.contains("DIR* opendir(const char* name);"));
822 assert!(result.contains("struct dirent* readdir(DIR* dirp);"));
823 assert!(result.contains("int closedir(DIR* dirp);"));
824 }
825
826 #[test]
831 fn test_inject_header_sys_types_definitions() {
832 let stdlib = StdlibPrototypes::new();
833 let result = stdlib.inject_prototypes_for_header(StdHeader::SysTypes);
834 assert!(result.contains("typedef int pid_t;"));
835 assert!(result.contains("typedef long off_t;"));
836 assert!(result.contains("typedef unsigned int mode_t;"));
837 assert!(result.contains("typedef long ssize_t;"));
838 }
839
840 #[test]
845 fn test_inject_header_sys_stat_definitions() {
846 let stdlib = StdlibPrototypes::new();
847 let result = stdlib.inject_prototypes_for_header(StdHeader::SysStat);
848 assert!(result.contains("struct stat { long st_size; int st_mode; };"));
849 assert!(result.contains("#define S_ISREG(m)"));
850 assert!(result.contains("#define S_ISDIR(m)"));
851 }
852
853 #[test]
858 fn test_inject_header_sys_mman_macros() {
859 let stdlib = StdlibPrototypes::new();
860 let result = stdlib.inject_prototypes_for_header(StdHeader::SysMman);
861 assert!(result.contains("#define PROT_NONE 0"));
862 assert!(result.contains("#define PROT_READ 1"));
863 assert!(result.contains("#define PROT_WRITE 2"));
864 assert!(result.contains("#define PROT_EXEC 4"));
865 assert!(result.contains("#define MAP_SHARED 1"));
866 assert!(result.contains("#define MAP_PRIVATE 2"));
867 assert!(result.contains("#define MAP_ANONYMOUS 0x20"));
868 assert!(result.contains("#define MAP_FAILED ((void*)-1)"));
869 }
870
871 #[test]
876 fn test_inject_header_wchar_definitions() {
877 let stdlib = StdlibPrototypes::new();
878 let result = stdlib.inject_prototypes_for_header(StdHeader::Wchar);
879 assert!(result.contains("typedef int wchar_t;"));
880 assert!(result.contains("typedef int wint_t;"));
881 assert!(result.contains("#define WEOF (-1)"));
882 }
883
884 #[test]
889 fn test_inject_header_signal_definitions() {
890 let stdlib = StdlibPrototypes::new();
891 let result = stdlib.inject_prototypes_for_header(StdHeader::Signal);
892 assert!(result.contains("typedef void (*sighandler_t)(int);"));
893 assert!(result.contains("#define SIGINT 2"));
894 assert!(result.contains("#define SIGTERM 15"));
895 }
896
897 #[test]
902 fn test_inject_header_limits_macros() {
903 let stdlib = StdlibPrototypes::new();
904 let result = stdlib.inject_prototypes_for_header(StdHeader::Limits);
905 assert!(result.contains("#define CHAR_BIT 8"));
906 assert!(result.contains("#define CHAR_MIN (-128)"));
907 assert!(result.contains("#define CHAR_MAX 127"));
908 assert!(result.contains("#define SHRT_MIN (-32768)"));
909 assert!(result.contains("#define SHRT_MAX 32767"));
910 assert!(result.contains("#define INT_MIN (-2147483647-1)"));
911 assert!(result.contains("#define INT_MAX 2147483647"));
912 assert!(result.contains("#define UINT_MAX 4294967295U"));
913 assert!(result.contains("#define LONG_MIN (-9223372036854775807L-1)"));
914 assert!(result.contains("#define LONG_MAX 9223372036854775807L"));
915 assert!(result.contains("#define PATH_MAX 4096"));
916 }
917
918 #[test]
923 fn test_inject_header_ctype_functions() {
924 let stdlib = StdlibPrototypes::new();
925 let result = stdlib.inject_prototypes_for_header(StdHeader::Ctype);
926 assert!(result.contains("int isspace(int c);"));
927 assert!(result.contains("int isdigit(int c);"));
928 assert!(result.contains("int isalpha(int c);"));
929 assert!(result.contains("int isalnum(int c);"));
930 assert!(result.contains("int isupper(int c);"));
931 assert!(result.contains("int islower(int c);"));
932 assert!(result.contains("int tolower(int c);"));
933 assert!(result.contains("int toupper(int c);"));
934 }
935
936 #[test]
937 fn test_inject_header_ctype_no_extra_type_defs() {
938 let stdlib = StdlibPrototypes::new();
939 let result = stdlib.inject_prototypes_for_header(StdHeader::Ctype);
940 assert!(!result.contains("typedef struct _IO_FILE FILE;"));
942 assert!(!result.contains("typedef long time_t;"));
943 }
944
945 #[test]
950 fn test_inject_header_math_macros() {
951 let stdlib = StdlibPrototypes::new();
952 let result = stdlib.inject_prototypes_for_header(StdHeader::Math);
953 assert!(result.contains("#define M_PI 3.14159265358979323846"));
954 assert!(result.contains("#define M_E 2.71828182845904523536"));
955 assert!(result.contains("#define INFINITY (1.0/0.0)"));
956 assert!(result.contains("#define NAN (0.0/0.0)"));
957 }
958
959 #[test]
960 fn test_inject_header_math_trig_functions() {
961 let stdlib = StdlibPrototypes::new();
962 let result = stdlib.inject_prototypes_for_header(StdHeader::Math);
963 assert!(result.contains("double sin(double x);"));
964 assert!(result.contains("double cos(double x);"));
965 assert!(result.contains("double tan(double x);"));
966 assert!(result.contains("double asin(double x);"));
967 assert!(result.contains("double acos(double x);"));
968 assert!(result.contains("double atan(double x);"));
969 assert!(result.contains("double atan2(double y, double x);"));
970 }
971
972 #[test]
973 fn test_inject_header_math_power_and_log_functions() {
974 let stdlib = StdlibPrototypes::new();
975 let result = stdlib.inject_prototypes_for_header(StdHeader::Math);
976 assert!(result.contains("double sqrt(double x);"));
977 assert!(result.contains("double pow(double x, double y);"));
978 assert!(result.contains("double exp(double x);"));
979 assert!(result.contains("double log(double x);"));
980 assert!(result.contains("double log10(double x);"));
981 }
982
983 #[test]
984 fn test_inject_header_math_rounding_functions() {
985 let stdlib = StdlibPrototypes::new();
986 let result = stdlib.inject_prototypes_for_header(StdHeader::Math);
987 assert!(result.contains("double fabs(double x);"));
988 assert!(result.contains("double ceil(double x);"));
989 assert!(result.contains("double floor(double x);"));
990 assert!(result.contains("double round(double x);"));
991 assert!(result.contains("double trunc(double x);"));
992 assert!(result.contains("double fmod(double x, double y);"));
993 }
994
995 #[test]
1000 fn test_inject_header_assert_has_common_preamble() {
1001 let stdlib = StdlibPrototypes::new();
1002 let result = stdlib.inject_prototypes_for_header(StdHeader::Assert);
1003 assert!(result.contains("// Built-in prototypes for Assert"));
1005 assert!(result.contains("typedef unsigned long size_t;"));
1006 assert!(result.contains("#define NULL 0"));
1007 }
1008
1009 #[test]
1010 fn test_inject_header_assert_no_header_specific_types() {
1011 let stdlib = StdlibPrototypes::new();
1012 let result = stdlib.inject_prototypes_for_header(StdHeader::Assert);
1013 assert!(!result.contains("typedef struct _IO_FILE FILE;"));
1015 assert!(!result.contains("typedef long time_t;"));
1016 assert!(!result.contains("extern int errno;"));
1017 }
1018
1019 #[test]
1024 fn test_inject_header_float_has_common_preamble() {
1025 let stdlib = StdlibPrototypes::new();
1026 let result = stdlib.inject_prototypes_for_header(StdHeader::Float);
1027 assert!(result.contains("// Built-in prototypes for Float"));
1028 assert!(result.contains("typedef unsigned long size_t;"));
1029 assert!(result.contains("#define NULL 0"));
1030 }
1031
1032 #[test]
1033 fn test_inject_header_float_no_functions() {
1034 let stdlib = StdlibPrototypes::new();
1035 let result = stdlib.inject_prototypes_for_header(StdHeader::Float);
1036 assert!(!result.contains("double sin("));
1038 assert!(!result.contains("int printf("));
1039 }
1040
1041 #[test]
1046 fn test_inject_header_locale_has_common_preamble() {
1047 let stdlib = StdlibPrototypes::new();
1048 let result = stdlib.inject_prototypes_for_header(StdHeader::Locale);
1049 assert!(result.contains("// Built-in prototypes for Locale"));
1050 assert!(result.contains("typedef unsigned long size_t;"));
1051 }
1052
1053 #[test]
1058 fn test_inject_header_setjmp_has_common_preamble() {
1059 let stdlib = StdlibPrototypes::new();
1060 let result = stdlib.inject_prototypes_for_header(StdHeader::Setjmp);
1061 assert!(result.contains("// Built-in prototypes for Setjmp"));
1062 assert!(result.contains("typedef unsigned long size_t;"));
1063 }
1064
1065 #[test]
1070 fn test_inject_header_stddef_has_common_preamble() {
1071 let stdlib = StdlibPrototypes::new();
1072 let result = stdlib.inject_prototypes_for_header(StdHeader::Stddef);
1073 assert!(result.contains("// Built-in prototypes for Stddef"));
1074 assert!(result.contains("typedef unsigned long size_t;"));
1075 assert!(result.contains("typedef long ptrdiff_t;"));
1076 }
1077
1078 #[test]
1083 fn test_inject_header_stdlib_memory_functions() {
1084 let stdlib = StdlibPrototypes::new();
1085 let result = stdlib.inject_prototypes_for_header(StdHeader::Stdlib);
1086 assert!(result.contains("void* malloc(size_t size);"));
1087 assert!(result.contains("void* calloc(size_t nmemb, size_t size);"));
1088 assert!(result.contains("void* realloc(void* ptr, size_t size);"));
1089 assert!(result.contains("void free(void* ptr);"));
1090 }
1091
1092 #[test]
1093 fn test_inject_header_stdlib_conversion_functions() {
1094 let stdlib = StdlibPrototypes::new();
1095 let result = stdlib.inject_prototypes_for_header(StdHeader::Stdlib);
1096 assert!(result.contains("int atoi(const char* nptr);"));
1097 assert!(result.contains("long atol(const char* nptr);"));
1098 assert!(result.contains("double atof(const char* nptr);"));
1099 assert!(result.contains("long strtol(const char* nptr, char** endptr, int base);"));
1100 assert!(result.contains("double strtod(const char* nptr, char** endptr);"));
1101 }
1102
1103 #[test]
1104 fn test_inject_header_stdlib_process_functions() {
1105 let stdlib = StdlibPrototypes::new();
1106 let result = stdlib.inject_prototypes_for_header(StdHeader::Stdlib);
1107 assert!(result.contains("void exit(int status);"));
1108 assert!(result.contains("void abort(void);"));
1109 assert!(result.contains("char* getenv(const char* name);"));
1110 assert!(result.contains("int system(const char* command);"));
1111 }
1112
1113 #[test]
1114 fn test_inject_header_stdlib_random_functions() {
1115 let stdlib = StdlibPrototypes::new();
1116 let result = stdlib.inject_prototypes_for_header(StdHeader::Stdlib);
1117 assert!(result.contains("int rand(void);"));
1118 assert!(result.contains("void srand(unsigned int seed);"));
1119 }
1120
1121 #[test]
1122 fn test_inject_header_stdlib_arithmetic_functions() {
1123 let stdlib = StdlibPrototypes::new();
1124 let result = stdlib.inject_prototypes_for_header(StdHeader::Stdlib);
1125 assert!(result.contains("int abs(int j);"));
1126 assert!(result.contains("long labs(long j);"));
1127 }
1128
1129 #[test]
1130 fn test_inject_header_stdlib_skips_function_pointer_params() {
1131 let stdlib = StdlibPrototypes::new();
1132 let result = stdlib.inject_prototypes_for_header(StdHeader::Stdlib);
1133 assert!(
1135 !result.contains("void qsort("),
1136 "qsort with function pointer param should be filtered out"
1137 );
1138 assert!(
1139 !result.contains("void* bsearch("),
1140 "bsearch with function pointer param should be filtered out"
1141 );
1142 }
1143
1144 #[test]
1145 fn test_inject_header_stdlib_does_not_contain_stdio_functions() {
1146 let stdlib = StdlibPrototypes::new();
1147 let result = stdlib.inject_prototypes_for_header(StdHeader::Stdlib);
1148 assert!(!result.contains("int printf("));
1149 assert!(!result.contains("FILE* fopen("));
1150 }
1151
1152 #[test]
1157 fn test_inject_header_string_copy_functions() {
1158 let stdlib = StdlibPrototypes::new();
1159 let result = stdlib.inject_prototypes_for_header(StdHeader::String);
1160 assert!(result.contains("void* memcpy(void* dest, const void* src, size_t n);"));
1161 assert!(result.contains("void* memmove(void* dest, const void* src, size_t n);"));
1162 assert!(result.contains("char* strcpy(char* dest, const char* src);"));
1163 assert!(result.contains("char* strncpy(char* dest, const char* src, size_t n);"));
1164 }
1165
1166 #[test]
1167 fn test_inject_header_string_concat_functions() {
1168 let stdlib = StdlibPrototypes::new();
1169 let result = stdlib.inject_prototypes_for_header(StdHeader::String);
1170 assert!(result.contains("char* strcat(char* dest, const char* src);"));
1171 assert!(result.contains("char* strncat(char* dest, const char* src, size_t n);"));
1172 }
1173
1174 #[test]
1175 fn test_inject_header_string_comparison_functions() {
1176 let stdlib = StdlibPrototypes::new();
1177 let result = stdlib.inject_prototypes_for_header(StdHeader::String);
1178 assert!(result.contains("int memcmp(const void* s1, const void* s2, size_t n);"));
1179 assert!(result.contains("int strcmp(const char* s1, const char* s2);"));
1180 assert!(result.contains("int strncmp(const char* s1, const char* s2, size_t n);"));
1181 }
1182
1183 #[test]
1184 fn test_inject_header_string_search_functions() {
1185 let stdlib = StdlibPrototypes::new();
1186 let result = stdlib.inject_prototypes_for_header(StdHeader::String);
1187 assert!(result.contains("void* memchr(const void* s, int c, size_t n);"));
1188 assert!(result.contains("char* strchr(const char* s, int c);"));
1189 assert!(result.contains("char* strrchr(const char* s, int c);"));
1190 assert!(result.contains("char* strstr(const char* haystack, const char* needle);"));
1191 assert!(result.contains("char* strtok(char* str, const char* delim);"));
1192 }
1193
1194 #[test]
1195 fn test_inject_header_string_misc_functions() {
1196 let stdlib = StdlibPrototypes::new();
1197 let result = stdlib.inject_prototypes_for_header(StdHeader::String);
1198 assert!(result.contains("void* memset(void* s, int c, size_t n);"));
1199 assert!(result.contains("size_t strlen(const char* s);"));
1200 assert!(result.contains("char* strdup(const char* s);"));
1201 }
1202
1203 #[test]
1204 fn test_inject_header_string_does_not_contain_math() {
1205 let stdlib = StdlibPrototypes::new();
1206 let result = stdlib.inject_prototypes_for_header(StdHeader::String);
1207 assert!(!result.contains("double sin("));
1208 assert!(!result.contains("#define M_PI"));
1209 }
1210
1211 #[test]
1216 fn test_inject_header_isolation_no_cross_contamination() {
1217 let stdlib = StdlibPrototypes::new();
1218
1219 let stdio_result = stdlib.inject_prototypes_for_header(StdHeader::Stdio);
1221 let string_result = stdlib.inject_prototypes_for_header(StdHeader::String);
1222 let math_result = stdlib.inject_prototypes_for_header(StdHeader::Math);
1223 let ctype_result = stdlib.inject_prototypes_for_header(StdHeader::Ctype);
1224
1225 assert!(!stdio_result.contains("size_t strlen("));
1227 assert!(!stdio_result.contains("void* memcpy("));
1228
1229 assert!(!string_result.contains("int printf("));
1231 assert!(!string_result.contains("FILE* fopen("));
1232
1233 assert!(!math_result.contains("int isspace("));
1235 assert!(!math_result.contains("int toupper("));
1236
1237 assert!(!ctype_result.contains("double sqrt("));
1239 assert!(!ctype_result.contains("#define M_PI"));
1240 }
1241
1242 #[test]
1243 fn test_inject_header_functions_are_sorted_alphabetically() {
1244 let stdlib = StdlibPrototypes::new();
1245 let result = stdlib.inject_prototypes_for_header(StdHeader::String);
1246
1247 let memchr_pos = result.find("void* memchr(").unwrap();
1249 let memcmp_pos = result.find("int memcmp(").unwrap();
1250 let memcpy_pos = result.find("void* memcpy(").unwrap();
1251 let strlen_pos = result.find("size_t strlen(").unwrap();
1252 let strstr_pos = result.find("char* strstr(").unwrap();
1253
1254 assert!(memchr_pos < memcmp_pos);
1255 assert!(memcmp_pos < memcpy_pos);
1256 assert!(memcpy_pos < strlen_pos);
1257 assert!(strlen_pos < strstr_pos);
1258 }
1259
1260 #[test]
1261 fn test_inject_header_comment_contains_header_name() {
1262 let stdlib = StdlibPrototypes::new();
1263
1264 let result = stdlib.inject_prototypes_for_header(StdHeader::Stdio);
1265 assert!(result.contains("// Built-in prototypes for Stdio"));
1266
1267 let result = stdlib.inject_prototypes_for_header(StdHeader::Math);
1268 assert!(result.contains("// Built-in prototypes for Math"));
1269
1270 let result = stdlib.inject_prototypes_for_header(StdHeader::SysMman);
1271 assert!(result.contains("// Built-in prototypes for SysMman"));
1272 }
1273
1274 #[test]
1275 fn test_inject_header_result_ends_with_declarations() {
1276 let stdlib = StdlibPrototypes::new();
1277 let result = stdlib.inject_prototypes_for_header(StdHeader::Stdlib);
1279 for line in result.lines() {
1281 if line.contains('(')
1282 && line.contains(')')
1283 && !line.starts_with("//")
1284 && !line.starts_with("#")
1285 && !line.starts_with("typedef")
1286 && !line.starts_with("struct")
1287 && !line.starts_with("extern")
1288 {
1289 assert!(
1290 line.ends_with(';'),
1291 "Function declaration line should end with semicolon: {}",
1292 line
1293 );
1294 }
1295 }
1296 }
1297}