anscom 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- anscom-0.4.0/PKG-INFO +60 -0
- anscom-0.4.0/README.md +38 -0
- anscom-0.4.0/anscom.c +367 -0
- anscom-0.4.0/anscom.egg-info/PKG-INFO +60 -0
- anscom-0.4.0/anscom.egg-info/SOURCES.txt +7 -0
- anscom-0.4.0/anscom.egg-info/dependency_links.txt +1 -0
- anscom-0.4.0/anscom.egg-info/top_level.txt +1 -0
- anscom-0.4.0/setup.cfg +4 -0
- anscom-0.4.0/setup.py +31 -0
anscom-0.4.0/PKG-INFO
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: anscom
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: A fast native C recursive file scanner and analyzer
|
|
5
|
+
Home-page: https://github.com/PC5518
|
|
6
|
+
Author: Aditya Narayan Singh
|
|
7
|
+
Author-email: adityansdsdc@outlook.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: C
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.6
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
Dynamic: author
|
|
15
|
+
Dynamic: author-email
|
|
16
|
+
Dynamic: classifier
|
|
17
|
+
Dynamic: description
|
|
18
|
+
Dynamic: description-content-type
|
|
19
|
+
Dynamic: home-page
|
|
20
|
+
Dynamic: requires-python
|
|
21
|
+
Dynamic: summary
|
|
22
|
+
|
|
23
|
+
# Anscom
|
|
24
|
+
|
|
25
|
+
**Anscom** is a high-performance, native C extension for Python that recursively scans directories and categorizes files with blazingly fast speed.
|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
- **Native C Speed:** Written in pure C (C89 compliant).
|
|
29
|
+
- **Visual Tree:** Prints a diagrammatic folder tree in the terminal.
|
|
30
|
+
- **Detailed Analysis:** Breakdowns by category and specific file extensions.
|
|
31
|
+
- **Cross-Platform:** Works on Windows, Linux, and macOS.
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
```bash
|
|
35
|
+
pip install anscom
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
Usage
|
|
40
|
+
code
|
|
41
|
+
Python
|
|
42
|
+
import anscom
|
|
43
|
+
|
|
44
|
+
# Scan the current directory
|
|
45
|
+
anscom.scan(".")
|
|
46
|
+
|
|
47
|
+
# Scan a specific path
|
|
48
|
+
anscom.scan("C:/Users/Documents")
|
|
49
|
+
code
|
|
50
|
+
Code
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
### Step 2: Create a `MANIFEST.in`
|
|
54
|
+
When you package C modules, Python needs to know exactly which source files to include. Create a file named `MANIFEST.in`:
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
include *.c
|
|
58
|
+
include *.h
|
|
59
|
+
include LICENSE
|
|
60
|
+
include README.md
|
anscom-0.4.0/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Anscom
|
|
2
|
+
|
|
3
|
+
**Anscom** is a high-performance, native C extension for Python that recursively scans directories and categorizes files with blazingly fast speed.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
- **Native C Speed:** Written in pure C (C89 compliant).
|
|
7
|
+
- **Visual Tree:** Prints a diagrammatic folder tree in the terminal.
|
|
8
|
+
- **Detailed Analysis:** Breakdowns by category and specific file extensions.
|
|
9
|
+
- **Cross-Platform:** Works on Windows, Linux, and macOS.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
```bash
|
|
13
|
+
pip install anscom
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
Usage
|
|
18
|
+
code
|
|
19
|
+
Python
|
|
20
|
+
import anscom
|
|
21
|
+
|
|
22
|
+
# Scan the current directory
|
|
23
|
+
anscom.scan(".")
|
|
24
|
+
|
|
25
|
+
# Scan a specific path
|
|
26
|
+
anscom.scan("C:/Users/Documents")
|
|
27
|
+
code
|
|
28
|
+
Code
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
### Step 2: Create a `MANIFEST.in`
|
|
32
|
+
When you package C modules, Python needs to know exactly which source files to include. Create a file named `MANIFEST.in`:
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
include *.c
|
|
36
|
+
include *.h
|
|
37
|
+
include LICENSE
|
|
38
|
+
include README.md
|
anscom-0.4.0/anscom.c
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* anscom.c
|
|
3
|
+
*
|
|
4
|
+
* Version: v0.4 (The Analyst Edition)
|
|
5
|
+
* Description: Native Python extension with:
|
|
6
|
+
* 1. Visual Directory Tree Map
|
|
7
|
+
* 2. Category Summary
|
|
8
|
+
* 3. Detailed Extension Breakdown
|
|
9
|
+
*
|
|
10
|
+
* Compilation: python setup.py build_ext --inplace
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
#define PY_SSIZE_T_CLEAN
|
|
14
|
+
#include <Python.h>
|
|
15
|
+
#include <stdio.h>
|
|
16
|
+
#include <stdlib.h>
|
|
17
|
+
#include <string.h>
|
|
18
|
+
#include <ctype.h>
|
|
19
|
+
|
|
20
|
+
/* Cross-platform headers */
|
|
21
|
+
#ifdef _WIN32
|
|
22
|
+
#include <windows.h>
|
|
23
|
+
#define PATH_SEP '\\'
|
|
24
|
+
#else
|
|
25
|
+
#include <dirent.h>
|
|
26
|
+
#include <sys/stat.h>
|
|
27
|
+
#include <unistd.h>
|
|
28
|
+
#define PATH_SEP '/'
|
|
29
|
+
#endif
|
|
30
|
+
|
|
31
|
+
/* -------------------------------------------------------------------------
|
|
32
|
+
Data Structures
|
|
33
|
+
------------------------------------------------------------------------- */
|
|
34
|
+
|
|
35
|
+
typedef enum {
|
|
36
|
+
CAT_CODE = 0,
|
|
37
|
+
CAT_DOCUMENT,
|
|
38
|
+
CAT_IMAGE,
|
|
39
|
+
CAT_VIDEO,
|
|
40
|
+
CAT_AUDIO,
|
|
41
|
+
CAT_ARCHIVE,
|
|
42
|
+
CAT_EXECUTABLE,
|
|
43
|
+
CAT_SYSTEM,
|
|
44
|
+
CAT_UNKNOWN,
|
|
45
|
+
CAT_COUNT
|
|
46
|
+
} FileCategory;
|
|
47
|
+
|
|
48
|
+
static const char* CAT_NAMES[CAT_COUNT] = {
|
|
49
|
+
"Code/Source", "Documents", "Images", "Videos", "Audio",
|
|
50
|
+
"Archives", "Executables", "System/Config", "Other/Unknown"
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/*
|
|
54
|
+
* Modified Struct: Now holds a mutable 'count' for specific extensions
|
|
55
|
+
*/
|
|
56
|
+
typedef struct {
|
|
57
|
+
char ext[16]; /* File extension string */
|
|
58
|
+
FileCategory category; /* General Category */
|
|
59
|
+
unsigned long long count; /* Specific counter for this extension */
|
|
60
|
+
} ExtMap;
|
|
61
|
+
|
|
62
|
+
/*
|
|
63
|
+
* MASTER EXTENSION DATABASE
|
|
64
|
+
* Note: Not 'const' anymore because we update the 'count' inside it.
|
|
65
|
+
*/
|
|
66
|
+
static ExtMap EXTENSION_TABLE[] = {
|
|
67
|
+
{"3g2", CAT_VIDEO, 0}, {"3gp", CAT_VIDEO, 0}, {"7z", CAT_ARCHIVE, 0}, {"aac", CAT_AUDIO, 0},
|
|
68
|
+
{"accdb", CAT_DOCUMENT, 0}, {"ai", CAT_IMAGE, 0}, {"aif", CAT_AUDIO, 0}, {"apk", CAT_ARCHIVE, 0},
|
|
69
|
+
{"app", CAT_EXECUTABLE, 0}, {"asf", CAT_VIDEO, 0}, {"asm", CAT_CODE, 0}, {"asp", CAT_CODE, 0},
|
|
70
|
+
{"aspx", CAT_CODE, 0}, {"avi", CAT_VIDEO, 0}, {"avif", CAT_IMAGE, 0}, {"awk", CAT_CODE, 0},
|
|
71
|
+
{"bak", CAT_SYSTEM, 0}, {"bas", CAT_CODE, 0}, {"bat", CAT_CODE, 0}, {"bin", CAT_EXECUTABLE, 0},
|
|
72
|
+
{"bmp", CAT_IMAGE, 0}, {"bz2", CAT_ARCHIVE, 0}, {"c", CAT_CODE, 0}, {"cab", CAT_ARCHIVE, 0},
|
|
73
|
+
{"cbr", CAT_ARCHIVE, 0}, {"cc", CAT_CODE, 0}, {"cfg", CAT_SYSTEM, 0}, {"class", CAT_EXECUTABLE, 0},
|
|
74
|
+
{"cmd", CAT_CODE, 0}, {"cnf", CAT_SYSTEM, 0}, {"com", CAT_EXECUTABLE, 0}, {"conf", CAT_SYSTEM, 0},
|
|
75
|
+
{"cpp", CAT_CODE, 0}, {"cr2", CAT_IMAGE, 0}, {"crt", CAT_SYSTEM, 0}, {"cs", CAT_CODE, 0},
|
|
76
|
+
{"css", CAT_CODE, 0}, {"csv", CAT_DOCUMENT, 0}, {"cue", CAT_AUDIO, 0}, {"cur", CAT_IMAGE, 0},
|
|
77
|
+
{"dat", CAT_SYSTEM, 0}, {"db", CAT_SYSTEM, 0}, {"dbf", CAT_DOCUMENT, 0}, {"deb", CAT_ARCHIVE, 0},
|
|
78
|
+
{"dll", CAT_EXECUTABLE, 0}, {"dmg", CAT_ARCHIVE, 0}, {"doc", CAT_DOCUMENT, 0}, {"docx", CAT_DOCUMENT, 0},
|
|
79
|
+
{"dot", CAT_DOCUMENT, 0}, {"dotx", CAT_DOCUMENT, 0}, {"drw", CAT_IMAGE, 0}, {"dxf", CAT_IMAGE, 0},
|
|
80
|
+
{"ebook", CAT_DOCUMENT, 0}, {"elf", CAT_EXECUTABLE, 0}, {"eml", CAT_DOCUMENT, 0}, {"env", CAT_SYSTEM, 0},
|
|
81
|
+
{"eps", CAT_IMAGE, 0}, {"epub", CAT_DOCUMENT, 0}, {"exe", CAT_EXECUTABLE, 0}, {"flac", CAT_AUDIO, 0},
|
|
82
|
+
{"flv", CAT_VIDEO, 0}, {"fnt", CAT_SYSTEM, 0}, {"fon", CAT_SYSTEM, 0}, {"fth", CAT_CODE, 0},
|
|
83
|
+
{"gif", CAT_IMAGE, 0}, {"git", CAT_SYSTEM, 0}, {"gitignore", CAT_SYSTEM, 0}, {"go", CAT_CODE, 0},
|
|
84
|
+
{"gpg", CAT_SYSTEM, 0}, {"gradle", CAT_CODE, 0}, {"groovy", CAT_CODE, 0}, {"gz", CAT_ARCHIVE, 0},
|
|
85
|
+
{"h", CAT_CODE, 0}, {"heic", CAT_IMAGE, 0}, {"heif", CAT_IMAGE, 0}, {"hpp", CAT_CODE, 0},
|
|
86
|
+
{"htm", CAT_CODE, 0}, {"html", CAT_CODE, 0}, {"hwp", CAT_DOCUMENT, 0}, {"ico", CAT_IMAGE, 0},
|
|
87
|
+
{"ics", CAT_DOCUMENT, 0}, {"iff", CAT_IMAGE, 0}, {"img", CAT_ARCHIVE, 0}, {"indd", CAT_DOCUMENT, 0},
|
|
88
|
+
{"ini", CAT_SYSTEM, 0}, {"iso", CAT_ARCHIVE, 0}, {"jar", CAT_ARCHIVE, 0}, {"java", CAT_CODE, 0},
|
|
89
|
+
{"jpeg", CAT_IMAGE, 0}, {"jpg", CAT_IMAGE, 0}, {"js", CAT_CODE, 0}, {"json", CAT_CODE, 0},
|
|
90
|
+
{"jsp", CAT_CODE, 0}, {"jsx", CAT_CODE, 0}, {"key", CAT_DOCUMENT, 0}, {"kt", CAT_CODE, 0},
|
|
91
|
+
{"kts", CAT_CODE, 0}, {"less", CAT_CODE, 0}, {"log", CAT_SYSTEM, 0}, {"lua", CAT_CODE, 0},
|
|
92
|
+
{"m", CAT_CODE, 0}, {"m3u", CAT_AUDIO, 0}, {"m4a", CAT_AUDIO, 0}, {"m4v", CAT_VIDEO, 0},
|
|
93
|
+
{"mak", CAT_CODE, 0}, {"md", CAT_DOCUMENT, 0}, {"mdb", CAT_DOCUMENT, 0}, {"mid", CAT_AUDIO, 0},
|
|
94
|
+
{"midi", CAT_AUDIO, 0}, {"mkv", CAT_VIDEO, 0}, {"mm", CAT_CODE, 0}, {"mobi", CAT_DOCUMENT, 0},
|
|
95
|
+
{"mov", CAT_VIDEO, 0}, {"mp3", CAT_AUDIO, 0}, {"mp4", CAT_VIDEO, 0}, {"mpeg", CAT_VIDEO, 0},
|
|
96
|
+
{"mpg", CAT_VIDEO, 0}, {"msi", CAT_EXECUTABLE, 0}, {"nef", CAT_IMAGE, 0}, {"numbers", CAT_DOCUMENT, 0},
|
|
97
|
+
{"obj", CAT_SYSTEM, 0}, {"odp", CAT_DOCUMENT, 0}, {"ods", CAT_DOCUMENT, 0}, {"odt", CAT_DOCUMENT, 0},
|
|
98
|
+
{"ogg", CAT_AUDIO, 0}, {"ogv", CAT_VIDEO, 0}, {"orf", CAT_IMAGE, 0}, {"otf", CAT_SYSTEM, 0},
|
|
99
|
+
{"pages", CAT_DOCUMENT, 0}, {"pak", CAT_ARCHIVE, 0}, {"pas", CAT_CODE, 0}, {"pdf", CAT_DOCUMENT, 0},
|
|
100
|
+
{"pem", CAT_SYSTEM, 0}, {"php", CAT_CODE, 0}, {"pkg", CAT_ARCHIVE, 0}, {"pl", CAT_CODE, 0},
|
|
101
|
+
{"pm", CAT_CODE, 0}, {"png", CAT_IMAGE, 0}, {"ppt", CAT_DOCUMENT, 0}, {"pptx", CAT_DOCUMENT, 0},
|
|
102
|
+
{"ps", CAT_IMAGE, 0}, {"ps1", CAT_CODE, 0}, {"psd", CAT_IMAGE, 0}, {"pub", CAT_DOCUMENT, 0},
|
|
103
|
+
{"py", CAT_CODE, 0}, {"pyc", CAT_SYSTEM, 0}, {"pyd", CAT_EXECUTABLE, 0}, {"pyw", CAT_CODE, 0},
|
|
104
|
+
{"r", CAT_CODE, 0}, {"rar", CAT_ARCHIVE, 0}, {"raw", CAT_IMAGE, 0}, {"rb", CAT_CODE, 0},
|
|
105
|
+
{"reg", CAT_SYSTEM, 0}, {"rm", CAT_VIDEO, 0}, {"rpm", CAT_ARCHIVE, 0}, {"rs", CAT_CODE, 0},
|
|
106
|
+
{"rst", CAT_DOCUMENT, 0}, {"rtf", CAT_DOCUMENT, 0}, {"sass", CAT_CODE, 0}, {"scala", CAT_CODE, 0},
|
|
107
|
+
{"scss", CAT_CODE, 0}, {"sh", CAT_CODE, 0}, {"sln", CAT_CODE, 0}, {"so", CAT_EXECUTABLE, 0},
|
|
108
|
+
{"sql", CAT_CODE, 0}, {"srt", CAT_VIDEO, 0}, {"svg", CAT_IMAGE, 0}, {"swf", CAT_VIDEO, 0},
|
|
109
|
+
{"swift", CAT_CODE, 0}, {"sys", CAT_SYSTEM, 0}, {"tar", CAT_ARCHIVE, 0}, {"tga", CAT_IMAGE, 0},
|
|
110
|
+
{"tgz", CAT_ARCHIVE, 0}, {"tif", CAT_IMAGE, 0}, {"tiff", CAT_IMAGE, 0}, {"tmp", CAT_SYSTEM, 0},
|
|
111
|
+
{"ts", CAT_CODE, 0}, {"tsv", CAT_DOCUMENT, 0}, {"ttf", CAT_SYSTEM, 0}, {"txt", CAT_DOCUMENT, 0},
|
|
112
|
+
{"vb", CAT_CODE, 0}, {"vbox", CAT_SYSTEM, 0}, {"vcd", CAT_ARCHIVE, 0}, {"vcf", CAT_DOCUMENT, 0},
|
|
113
|
+
{"vcxproj", CAT_CODE, 0}, {"vob", CAT_VIDEO, 0}, {"vue", CAT_CODE, 0}, {"wav", CAT_AUDIO, 0},
|
|
114
|
+
{"webm", CAT_VIDEO, 0}, {"webp", CAT_IMAGE, 0}, {"wma", CAT_AUDIO, 0}, {"wmv", CAT_VIDEO, 0},
|
|
115
|
+
{"woff", CAT_SYSTEM, 0}, {"woff2", CAT_SYSTEM, 0}, {"wpd", CAT_DOCUMENT, 0}, {"wps", CAT_DOCUMENT, 0},
|
|
116
|
+
{"wsf", CAT_CODE, 0}, {"xcodeproj", CAT_CODE, 0}, {"xls", CAT_DOCUMENT, 0}, {"xlsm", CAT_DOCUMENT, 0},
|
|
117
|
+
{"xlsx", CAT_DOCUMENT, 0}, {"xml", CAT_CODE, 0}, {"yaml", CAT_CODE, 0}, {"yml", CAT_CODE, 0},
|
|
118
|
+
{"zip", CAT_ARCHIVE, 0}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
static const int EXTENSION_COUNT = sizeof(EXTENSION_TABLE) / sizeof(ExtMap);
|
|
122
|
+
|
|
123
|
+
typedef struct {
|
|
124
|
+
unsigned long long counts[CAT_COUNT];
|
|
125
|
+
unsigned long long total_files;
|
|
126
|
+
} ScanStats;
|
|
127
|
+
|
|
128
|
+
/* -------------------------------------------------------------------------
|
|
129
|
+
Helper Functions
|
|
130
|
+
------------------------------------------------------------------------- */
|
|
131
|
+
|
|
132
|
+
static int compare_ext(const void *key, const void *elem) {
|
|
133
|
+
const char *k = (const char *)key;
|
|
134
|
+
const ExtMap *m = (const ExtMap *)elem;
|
|
135
|
+
return strcmp(k, m->ext);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
static FileCategory identify_and_count(const char *filename) {
|
|
139
|
+
const char *dot = strrchr(filename, '.');
|
|
140
|
+
char ext_lower[32];
|
|
141
|
+
const char *ext_ptr;
|
|
142
|
+
size_t i = 0;
|
|
143
|
+
ExtMap *found;
|
|
144
|
+
|
|
145
|
+
if (!dot || dot == filename) return CAT_UNKNOWN;
|
|
146
|
+
ext_ptr = dot + 1;
|
|
147
|
+
|
|
148
|
+
while (ext_ptr[i] && i < 31) {
|
|
149
|
+
ext_lower[i] = tolower((unsigned char)ext_ptr[i]);
|
|
150
|
+
i++;
|
|
151
|
+
}
|
|
152
|
+
ext_lower[i] = '\0';
|
|
153
|
+
|
|
154
|
+
if (i == 0) return CAT_UNKNOWN;
|
|
155
|
+
|
|
156
|
+
/* Binary Search */
|
|
157
|
+
found = (ExtMap *)bsearch(ext_lower, EXTENSION_TABLE, EXTENSION_COUNT, sizeof(ExtMap), compare_ext);
|
|
158
|
+
|
|
159
|
+
if (found) {
|
|
160
|
+
found->count++; /* Increment specific extension counter */
|
|
161
|
+
return found->category;
|
|
162
|
+
}
|
|
163
|
+
return CAT_UNKNOWN;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/* Print Visual Tree Indentation */
|
|
167
|
+
static void print_tree_prefix(int depth) {
|
|
168
|
+
int i;
|
|
169
|
+
for (i = 0; i < depth; i++) {
|
|
170
|
+
printf(" | ");
|
|
171
|
+
}
|
|
172
|
+
printf(" |-- ");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* -------------------------------------------------------------------------
|
|
176
|
+
Core Scanning Logic
|
|
177
|
+
------------------------------------------------------------------------- */
|
|
178
|
+
|
|
179
|
+
#ifdef _WIN32
|
|
180
|
+
static void scan_recursive(const wchar_t *path, ScanStats *stats, int depth) {
|
|
181
|
+
WIN32_FIND_DATAW findData;
|
|
182
|
+
HANDLE hFind;
|
|
183
|
+
wchar_t searchPath[32768];
|
|
184
|
+
wchar_t subPath[32768];
|
|
185
|
+
char filenameUtf8[1024];
|
|
186
|
+
int ret;
|
|
187
|
+
FileCategory cat;
|
|
188
|
+
|
|
189
|
+
if (wcslen(path) + 3 >= 32768) return;
|
|
190
|
+
swprintf(searchPath, 32768, L"%s\\*", path);
|
|
191
|
+
|
|
192
|
+
hFind = FindFirstFileW(searchPath, &findData);
|
|
193
|
+
if (hFind == INVALID_HANDLE_VALUE) return;
|
|
194
|
+
|
|
195
|
+
do {
|
|
196
|
+
if (wcscmp(findData.cFileName, L".") == 0 || wcscmp(findData.cFileName, L"..") == 0)
|
|
197
|
+
continue;
|
|
198
|
+
|
|
199
|
+
/* Prepare UTF-8 name for display/logic */
|
|
200
|
+
ret = WideCharToMultiByte(CP_UTF8, 0, findData.cFileName, -1,
|
|
201
|
+
filenameUtf8, sizeof(filenameUtf8), NULL, NULL);
|
|
202
|
+
|
|
203
|
+
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
204
|
+
/* Diagrammatic Output for Folder */
|
|
205
|
+
if (ret > 0) {
|
|
206
|
+
print_tree_prefix(depth);
|
|
207
|
+
printf("[%s]\n", filenameUtf8);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (wcslen(path) + wcslen(findData.cFileName) + 2 < 32768) {
|
|
211
|
+
swprintf(subPath, 32768, L"%s\\%s", path, findData.cFileName);
|
|
212
|
+
scan_recursive(subPath, stats, depth + 1);
|
|
213
|
+
}
|
|
214
|
+
} else {
|
|
215
|
+
/* File handling */
|
|
216
|
+
if (ret > 0) {
|
|
217
|
+
cat = identify_and_count(filenameUtf8);
|
|
218
|
+
stats->counts[cat]++;
|
|
219
|
+
stats->total_files++;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
} while (FindNextFileW(hFind, &findData) != 0);
|
|
223
|
+
|
|
224
|
+
FindClose(hFind);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
#else
|
|
228
|
+
static void scan_recursive(const char *path, ScanStats *stats, int depth) {
|
|
229
|
+
DIR *dir;
|
|
230
|
+
struct dirent *entry;
|
|
231
|
+
char full_path[4096];
|
|
232
|
+
struct stat path_stat;
|
|
233
|
+
FileCategory cat;
|
|
234
|
+
|
|
235
|
+
if (!(dir = opendir(path))) return;
|
|
236
|
+
|
|
237
|
+
while ((entry = readdir(dir)) != NULL) {
|
|
238
|
+
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
|
239
|
+
continue;
|
|
240
|
+
|
|
241
|
+
if (snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name) >= (int)sizeof(full_path))
|
|
242
|
+
continue;
|
|
243
|
+
|
|
244
|
+
if (lstat(full_path, &path_stat) != 0) continue;
|
|
245
|
+
|
|
246
|
+
if (S_ISDIR(path_stat.st_mode)) {
|
|
247
|
+
/* Diagrammatic Output */
|
|
248
|
+
print_tree_prefix(depth);
|
|
249
|
+
printf("[%s]\n", entry->d_name);
|
|
250
|
+
scan_recursive(full_path, stats, depth + 1);
|
|
251
|
+
} else if (S_ISREG(path_stat.st_mode)) {
|
|
252
|
+
cat = identify_and_count(entry->d_name);
|
|
253
|
+
stats->counts[cat]++;
|
|
254
|
+
stats->total_files++;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
closedir(dir);
|
|
258
|
+
}
|
|
259
|
+
#endif
|
|
260
|
+
|
|
261
|
+
/* -------------------------------------------------------------------------
|
|
262
|
+
Python Interface
|
|
263
|
+
------------------------------------------------------------------------- */
|
|
264
|
+
|
|
265
|
+
static PyObject* anscom_scan(PyObject *self, PyObject *args) {
|
|
266
|
+
const char *input_path;
|
|
267
|
+
ScanStats stats;
|
|
268
|
+
int i;
|
|
269
|
+
double percent;
|
|
270
|
+
#ifdef _WIN32
|
|
271
|
+
int wlen;
|
|
272
|
+
wchar_t *wpath;
|
|
273
|
+
#endif
|
|
274
|
+
|
|
275
|
+
/* Reset global stats */
|
|
276
|
+
memset(&stats, 0, sizeof(stats));
|
|
277
|
+
for (i = 0; i < EXTENSION_COUNT; i++) {
|
|
278
|
+
EXTENSION_TABLE[i].count = 0;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (!PyArg_ParseTuple(args, "s", &input_path)) {
|
|
282
|
+
return NULL;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
printf("\nAnscom Analyst v0.4\n");
|
|
286
|
+
printf("Target: %s\n", input_path);
|
|
287
|
+
printf("Structure Map:\n");
|
|
288
|
+
printf(".\n"); /* Root dot */
|
|
289
|
+
|
|
290
|
+
#ifdef _WIN32
|
|
291
|
+
wlen = MultiByteToWideChar(CP_UTF8, 0, input_path, -1, NULL, 0);
|
|
292
|
+
if (wlen > 0) {
|
|
293
|
+
wpath = (wchar_t *)malloc(wlen * sizeof(wchar_t));
|
|
294
|
+
if (wpath) {
|
|
295
|
+
MultiByteToWideChar(CP_UTF8, 0, input_path, -1, wpath, wlen);
|
|
296
|
+
scan_recursive(wpath, &stats, 0);
|
|
297
|
+
free(wpath);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
#else
|
|
301
|
+
scan_recursive(input_path, &stats, 0);
|
|
302
|
+
#endif
|
|
303
|
+
|
|
304
|
+
/* 1. General Summary Table */
|
|
305
|
+
printf("\n");
|
|
306
|
+
printf("=== SUMMARY REPORT ================================\n");
|
|
307
|
+
printf("+-----------------+--------------+----------+\n");
|
|
308
|
+
printf("| %-15s | %-12s | %-8s |\n", "Category", "Count", "Percent");
|
|
309
|
+
printf("+-----------------+--------------+----------+\n");
|
|
310
|
+
|
|
311
|
+
if (stats.total_files == 0) {
|
|
312
|
+
printf("| %-38s |\n", "No files found.");
|
|
313
|
+
} else {
|
|
314
|
+
for (i = 0; i < CAT_COUNT; i++) {
|
|
315
|
+
if (stats.counts[i] == 0 && i != CAT_UNKNOWN) continue;
|
|
316
|
+
|
|
317
|
+
percent = (double)stats.counts[i] / (double)stats.total_files * 100.0;
|
|
318
|
+
printf("| %-15s | %12llu | %7.2f%% |\n",
|
|
319
|
+
CAT_NAMES[i],
|
|
320
|
+
stats.counts[i],
|
|
321
|
+
percent);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
printf("+-----------------+--------------+----------+\n");
|
|
325
|
+
printf("| %-15s | %12llu | %-8s |\n", "TOTAL FILES", stats.total_files, "100.00%");
|
|
326
|
+
printf("+-----------------+--------------+----------+\n");
|
|
327
|
+
|
|
328
|
+
/* 2. Detailed Extension Table */
|
|
329
|
+
if (stats.total_files > 0) {
|
|
330
|
+
printf("\n=== DETAILED BREAKDOWN ============================\n");
|
|
331
|
+
printf("+-----------------+--------------+\n");
|
|
332
|
+
printf("| %-15s | %-12s |\n", "Extension Type", "Count");
|
|
333
|
+
printf("+-----------------+--------------+\n");
|
|
334
|
+
|
|
335
|
+
for (i = 0; i < EXTENSION_COUNT; i++) {
|
|
336
|
+
if (EXTENSION_TABLE[i].count > 0) {
|
|
337
|
+
printf("| .%-14s | %12llu |\n",
|
|
338
|
+
EXTENSION_TABLE[i].ext,
|
|
339
|
+
EXTENSION_TABLE[i].count);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
printf("+-----------------+--------------+\n");
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return Py_BuildValue("K", stats.total_files);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/* -------------------------------------------------------------------------
|
|
349
|
+
Module Registration
|
|
350
|
+
------------------------------------------------------------------------- */
|
|
351
|
+
|
|
352
|
+
static PyMethodDef AnscomMethods[] = {
|
|
353
|
+
{"scan", anscom_scan, METH_VARARGS, "Scan directory with diagrammatic tree and detailed analysis."},
|
|
354
|
+
{NULL, NULL, 0, NULL}
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
static struct PyModuleDef anscommodule = {
|
|
358
|
+
PyModuleDef_HEAD_INIT,
|
|
359
|
+
"anscom",
|
|
360
|
+
"Analyst grade recursive file scanner.",
|
|
361
|
+
-1,
|
|
362
|
+
AnscomMethods
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
PyMODINIT_FUNC PyInit_anscom(void) {
|
|
366
|
+
return PyModule_Create(&anscommodule);
|
|
367
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: anscom
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: A fast native C recursive file scanner and analyzer
|
|
5
|
+
Home-page: https://github.com/PC5518
|
|
6
|
+
Author: Aditya Narayan Singh
|
|
7
|
+
Author-email: adityansdsdc@outlook.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: C
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.6
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
Dynamic: author
|
|
15
|
+
Dynamic: author-email
|
|
16
|
+
Dynamic: classifier
|
|
17
|
+
Dynamic: description
|
|
18
|
+
Dynamic: description-content-type
|
|
19
|
+
Dynamic: home-page
|
|
20
|
+
Dynamic: requires-python
|
|
21
|
+
Dynamic: summary
|
|
22
|
+
|
|
23
|
+
# Anscom
|
|
24
|
+
|
|
25
|
+
**Anscom** is a high-performance, native C extension for Python that recursively scans directories and categorizes files with blazingly fast speed.
|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
- **Native C Speed:** Written in pure C (C89 compliant).
|
|
29
|
+
- **Visual Tree:** Prints a diagrammatic folder tree in the terminal.
|
|
30
|
+
- **Detailed Analysis:** Breakdowns by category and specific file extensions.
|
|
31
|
+
- **Cross-Platform:** Works on Windows, Linux, and macOS.
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
```bash
|
|
35
|
+
pip install anscom
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
Usage
|
|
40
|
+
code
|
|
41
|
+
Python
|
|
42
|
+
import anscom
|
|
43
|
+
|
|
44
|
+
# Scan the current directory
|
|
45
|
+
anscom.scan(".")
|
|
46
|
+
|
|
47
|
+
# Scan a specific path
|
|
48
|
+
anscom.scan("C:/Users/Documents")
|
|
49
|
+
code
|
|
50
|
+
Code
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
### Step 2: Create a `MANIFEST.in`
|
|
54
|
+
When you package C modules, Python needs to know exactly which source files to include. Create a file named `MANIFEST.in`:
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
include *.c
|
|
58
|
+
include *.h
|
|
59
|
+
include LICENSE
|
|
60
|
+
include README.md
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
anscom
|
anscom-0.4.0/setup.cfg
ADDED
anscom-0.4.0/setup.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from setuptools import setup, Extension
|
|
2
|
+
|
|
3
|
+
# Read the long description from README
|
|
4
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
5
|
+
long_description = fh.read()
|
|
6
|
+
|
|
7
|
+
module = Extension(
|
|
8
|
+
'anscom',
|
|
9
|
+
sources=['anscom.c'],
|
|
10
|
+
# Optional: Compile arguments can be added here if needed
|
|
11
|
+
# extra_compile_args = ['-O3']
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
setup(
|
|
15
|
+
name='anscom', # Check PyPI if this name is taken!
|
|
16
|
+
version='0.4.0',
|
|
17
|
+
author='Aditya Narayan Singh',
|
|
18
|
+
author_email='adityansdsdc@outlook.com',
|
|
19
|
+
description='A fast native C recursive file scanner and analyzer',
|
|
20
|
+
long_description=long_description,
|
|
21
|
+
long_description_content_type="text/markdown",
|
|
22
|
+
url='https://github.com/PC5518', # Optional
|
|
23
|
+
ext_modules=[module],
|
|
24
|
+
classifiers=[
|
|
25
|
+
"Programming Language :: Python :: 3",
|
|
26
|
+
"Programming Language :: C",
|
|
27
|
+
"License :: OSI Approved :: MIT License",
|
|
28
|
+
"Operating System :: OS Independent",
|
|
29
|
+
],
|
|
30
|
+
python_requires='>=3.6',
|
|
31
|
+
)
|