flop_cli/
finder.rs

1use anyhow::{Context, Result};
2use regex::Regex;
3use std::fs;
4use std::path::Path;
5use walkdir::WalkDir;
6
7use crate::types::Match;
8
9pub fn find_debug_printfs(
10    path: &Path,
11    find_commented: bool,
12    detect_all: bool,
13) -> Result<Vec<Match>> {
14    let mut matches = Vec::new();
15
16    // Pattern to match C printf-like functions
17    let c_functions_pattern = if detect_all {
18        // Match all output functions regardless of content
19        Regex::new(
20            r"(printf|fprintf|sprintf|snprintf|printf_debug|dprintf|puts|fputs|fputc|putchar|fputchar|write|perror)\s*\([^;]*?;",
21        )?
22    } else {
23        // Match only those with "debug" or "DEBUG"
24        Regex::new(
25            r"(printf|fprintf|sprintf|snprintf|printf_debug|dprintf|puts|fputs|fputc|putchar|fputchar|write|perror)\s*\([^;]*?(debug|DEBUG)[^;]*?;",
26        )?
27    };
28
29    // Pattern to match C++ streams
30    let cpp_stream_pattern = if detect_all {
31        // Match all stream output regardless of content
32        Regex::new(r"(std::cout|std::cerr|std::clog)\s*<<[^;]*?;")?
33    } else {
34        // Match only those with "debug" or "DEBUG"
35        Regex::new(r"(std::cout|std::cerr|std::clog)\s*<<[^;]*?(debug|DEBUG)[^;]*?;")?
36    };
37
38    let comment_pattern = Regex::new(r"^\s*//")?;
39
40    let entries: Vec<_> = if path.is_file() {
41        vec![path.to_path_buf()]
42    } else {
43        WalkDir::new(path)
44            .into_iter()
45            .filter_map(|e| e.ok())
46            .filter(|e| {
47                e.path().is_file()
48                    && e.path()
49                        .extension()
50                        .and_then(|s| s.to_str())
51                        .map(|ext| matches!(ext, "c" | "h" | "cpp" | "hpp" | "cc" | "cxx"))
52                        .unwrap_or(false)
53            })
54            .map(|e| e.path().to_path_buf())
55            .collect()
56    };
57
58    for file_path in entries {
59        let content = fs::read_to_string(&file_path)
60            .with_context(|| format!("Failed to read file: {}", file_path.display()))?;
61
62        for (line_num, line) in content.lines().enumerate() {
63            let is_commented = comment_pattern.is_match(line);
64            let has_debug_output =
65                c_functions_pattern.is_match(line) || cpp_stream_pattern.is_match(line);
66
67            // Add to matches if it matches our search criteria
68            if has_debug_output && is_commented == find_commented {
69                matches.push(Match {
70                    file_path: file_path.clone(),
71                    line_number: line_num + 1,
72                    line_content: line.to_string(),
73                });
74            }
75        }
76    }
77
78    Ok(matches)
79}