- C-Template für CLI Tools
This commit is contained in:
Adam Skotarczak 2025-05-09 22:46:31 +02:00
commit 4a9b5e77f3
Signed by: realAscot
GPG Key ID: 4CB9B8D93A96A538
25 changed files with 720 additions and 0 deletions

12
.gitattributes vendored Normal file
View File

@ -0,0 +1,12 @@
# Quelltext immer mit Unix-Zeilenenden speichern (LF)
*.c text eol=lf
*.h text eol=lf
# Binärdateien
*.exe binary -diff
*.obj binary -diff
*.pdb binary -diff
*.ilk binary -diff
# Sprache für GitHub-Statistiken
*.h linguist-language=C

12
.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
/*.obj
/*.exe
/build/**
!.gitkeep
/*.obj
/*.exe
/*.ilk
/*.pdb
# Custom:
*.zip
/NOTES

18
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,18 @@
{
"configurations": [
{
"name": "windows-gcc-x64",
"includePath": [
"${workspaceFolder}/**"
],
"compilerPath": "cl",
"cStandard": "${default}",
"cppStandard": "${default}",
"intelliSenseMode": "windows-gcc-x64",
"compilerArgs": [
""
]
}
],
"version": 4
}

10
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,10 @@
{
"recommendations": [
"ms-vscode.cpptools", // C/C++ Support (IntelliSense, Debugging, CodeNav)
"aaron-bond.better-comments", // Verbesserte Kommentarfunktion
"usernamehw.errorlens", // Fehler direkt im Editor anzeigen
"eamodio.gitlens", // Git Integration (optional)
"actboy168.tasks", // Tasks Explorer GUI (optional)
"xaver.clang-format" // (optional) Automatische Formatierung mit clang-format
]
}

15
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug scanner.exe",
"type": "cppvsdbg",
"request": "launch",
"program": "${workspaceFolder}/build/output/treescanner.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"console": "externalTerminal"
}
]
}

7
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
"files.encoding": "utf8",
"files.eol": "\n",
"editor.tabSize": 4,
"editor.insertSpaces": true
}

19
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,19 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Build scanner.exe (MSVC)",
"type": "shell",
"command": "cmd.exe",
"args": [
"/c",
"build.cmd"
],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
}
]
}

27
LICENSE Normal file
View File

@ -0,0 +1,27 @@
# 📄 `LICENSE` (MIT)
```plaintext
MIT License
Copyright (c) 2025 Adam Skotarczak
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
```

103
README.md Normal file
View File

@ -0,0 +1,103 @@
# ⚙️ CLI-Template für C (MSVC)
Ein leichtgewichtiges C-Projekttemplate für die Kommandozeile unter Windows, vorbereitet für den Microsoft Visual C Compiler (MSVC).
## Inhalt
- [⚙️ CLI-Template für C (MSVC)](#-cli-template-für-c-msvc)
- [Inhalt](#inhalt)
- [Features](#features)
- [Struktur](#struktur)
- [Voraussetzungen](#voraussetzungen)
- [Nutzung](#nutzung)
- [Dokumentation](#dokumentation)
- [Plattformhinweis](#plattformhinweis)
---
## Features
- Rekursive Verzeichnissuche mit ASCII-Ausgabe
- Kompatibel mit `cl.exe` über `build.cmd`
- Debugging per `launch.json` (VS Code)
- Unicode-Ausgabe (📁 📄) für unterstützende Terminals
- Struktur für sauberen Code (main + Module)
[](#inhalt)
---
## Struktur
```plaintext
📁 treescanner # Projekt-Wurzelverzeichnis (Repository-Root)
📁 .vscode # Konfigurationsverzeichnis für Visual Studio Code
📄 c_cpp_properties.json # IntelliSense-Einstellungen (Compilerpfade, Defines etc.)
📄 extensions.json # Empfehlung installierbarer VS Code Extensions
📄 launch.json # Debug-Konfiguration (z.B. Programm, Argumente, Terminal)
📄 settings.json # Editor-spezifische Projekteinstellungen (z.B. Tabs, Formatierung)
📄 tasks.json # Build-Tasks (z.B. MSVC Build über build.cmd)
📁 build # Build-Artefakte (ausgabeorientiertes Verzeichnis)
📄 .gitkeep # Platzhalterdatei, damit Git leere Verzeichnisse behält
📁 output # Output-Ordner für kompilierte Binärdateien und Objekte
📄 app.obj # Objektdatei aus app.c
📄 main.obj # Objektdatei aus main.c
📄 treescanner.exe # Kompilierte lauffähige .exe-Datei
📄 build.cmd # Build-Skript für MSVC (ruft cl.exe via vcvars64.bat)
📄 clean.cmd # Hilfsskript zum Löschen von build/output
📁 include # Header-Dateien für Funktionsprototypen
📄 app.h # Deklaration von `scan_directory()`
📄 LICENSE # Lizenzdatei (hier: MIT License)
📄 README.md # Projektdokumentation (Nutzung, Build, Features etc.)
📁 src # Quellcode-Verzeichnis (.c-Dateien)
📄 app.c # Implementierung der rekursiven Verzeichnissuche
📄 main.c # Einstiegspunkt (main-Funktion)
📄 VERSION # Datei mit Versionsnummer (z.B. „0.1.0-dev“)
📄 .gitattributes # Git-spezifische Datei (z.B. Zeilenenden, Binärdateien, Sprache)
📄 .gitignore # Liste auszuschließender Dateien und Verzeichnisse (z.B. *.exe, /build/)
```
[](#inhalt)
---
## Voraussetzungen
- [Visual Studio Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/)
- MSVC `cl.exe` + `vcvars64.bat` korrekt eingebunden
[](#inhalt)
---
## Nutzung
```cmd
build.cmd
```
**Ausgabe:**
`build/output/scanner.exe`
[](#inhalt)
---
## Dokumentation
- [x] [C Code Style Guide für CLI-Projekte](./doc/code_style.md)
- [x] [Windows API Referenz CLI-Toolkit](./doc/index.md)
[](#inhalt)
---
## Plattformhinweis
> Dieses Projekt ist aktuell auf **Windows** ausgelegt (MSVC, Windows API).
> Es enthält jedoch bereits `#ifdef _WIN32`-Konstrukte zur Vorbereitung einer plattformübergreifenden Umsetzung.
> Die POSIX-Version (`opendir`, `readdir`) kann später leicht ergänzt werden.
[](#inhalt)
---

1
VERSION Normal file
View File

@ -0,0 +1 @@
1.0.0

15
build.cmd Normal file
View File

@ -0,0 +1,15 @@
@echo off
setlocal
chcp 65001 >nul
echo [INFO] Initialisiere MSVC Umgebung...
call "D:\windows\Programme\MSStudio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat"
echo [INFO] Baue Projekt...
cl /c src\main.c /I include /Fo:build\output\main.obj
cl /c src\app.c /I include /Fo:build\output\app.obj
link build\output\main.obj build\output\app.obj /OUT:build\output\treescanner.exe /PDB:build\output\treescanner.pdb
echo [OK] Build abgeschlossen.

0
build/.gitkeep Normal file
View File

7
clean.cmd Normal file
View File

@ -0,0 +1,7 @@
@echo off
chcp 65001 >nul
echo [INFO] Lösche build/output...
rmdir /s /q build\output 2>nul
mkdir build\output
echo [OK] Sauber.

92
doc/code_style.md Normal file
View File

@ -0,0 +1,92 @@
# C Code Style Guide für CLI-Projekte
## 🔧 Allgemeines
- **Zeichencodierung:** UTF-8 (ohne BOM)
- **Zeilenenden:** LF (`\n`) plattformunabhängig
- **Einrückung:** 4 Leerzeichen (keine Tabs)
- **Maximale Zeilenlänge:** 100 Zeichen (Ausnahme: ASCII-Bäume oder Formatstrings)
## 🧱 Präprozessor-Direktiven
```c
#ifndef APP_H
#define APP_H
// Keine Einrückung bei #define, #ifdef, #endif
// Kommentare nach #endif zur Orientierung bei größeren Headern
#endif // APP_H
```
## 📦 Header-Dateien (`.h`)
- Funktionsprototypen sind **nicht eingerückt**
- Kommentare über dem Prototyp mit Doxygen-Stil (`/** ... */`)
- Header Guards oder `#pragma once` aber nicht beides
```c
/**
* @brief Führt rekursive Verzeichnissuche durch.
*
* @param base_path Startpfad
* @param depth Rekursionstiefe (nur zur Einrückung)
*/
void scan_directory(const char *base_path, int depth);
```
## 🧠 Funktionen
```c
int main(int argc, char *argv[]) {
// Code beginnt eingerückt
if (argc > 1) {
printf("Pfad: %s\n", argv[1]);
}
return 0;
}
```
- **Funktionsklammern immer öffnend auf derselben Zeile**
- Immer mit Rückgabetyp (`void`, `int`, etc.)
- Keine leeren Parameterlisten → `void` verwenden (`int foo(void)`)
## 🌳 Einrückung & Blöcke
```c
if (ok) {
mach_was();
} else {
mach_anders();
}
```
- `if`, `else`, `while`, `for` immer mit `{}` auch bei einzeiligen Blöcken
- Klammern auf derselben Zeile
- Keine überflüssigen Leerzeilen innerhalb eines Blocks
## 🧾 Kommentare
- Doxygen-kompatibel für alles, was extern verwendet wird
- Inline-Kommentare nur bei **nicht sofort ersichtlicher Logik**
```c
// Rekursion starten, wenn Verzeichnis
scan_directory(sub_path, depth + 1);
```
## 📁 Dateibenennung
| Elementtyp | Beispiel |
|------------------|------------------|
| Header-Dateien | `app.h` |
| Implementierung | `app.c` |
| Main-Einstieg | `main.c` |
| Konstanten/Makros| `config.h` |
## 📚 Optionaler Zusatz für Tools
- Doxygen mit `Doxyfile`
- `clang-format` für Einrückung und Formatierung
- `cppcheck` für statische Analyse

33
doc/filetime.md Normal file
View File

@ -0,0 +1,33 @@
# FILETIME Strukturreferenz (Windows API)
Die `FILETIME`-Struktur repräsentiert Zeitangaben im Windows-Dateisystem in einer 64-Bit-Darstellung.
## Definition (aus `WinBase.h`)
```c
typedef struct _FILETIME {
DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME;
```
## Beschreibung
- `FILETIME` speichert eine Zeit als Anzahl der 100-Nanosekunden-Intervalle seit dem 1. Januar 1601 (UTC).
- Wird oft in Kombination mit `WIN32_FIND_DATA` oder `GetFileTime()` verwendet.
## Umwandlung in lesbare Zeit
```c
FILETIME ft;
// ...füllen durch API-Aufruf...
SYSTEMTIME st;
FileTimeToSystemTime(&ft, &st);
printf("%d-%02d-%02d %02d:%02d\n", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute);
```
## Hinweise
- In lokalen Zeitzonen konvertieren: `FileTimeToLocalFileTime()`
- Für High-Level-Zeitverarbeitung besser `SYSTEMTIME` oder `time_t` verwenden

32
doc/getlasterror.md Normal file
View File

@ -0,0 +1,32 @@
# GetLastError Fehlerdiagnose (Windows API)
`GetLastError()` liefert den Fehlercode des letzten fehlgeschlagenen Windows-API-Aufrufs.
## Definition
```c
DWORD GetLastError(void);
```
## Beispiel
```c
HANDLE hFile = CreateFile(...);
if (hFile == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
printf("Fehlercode: %lu\n", err);
}
```
## FormatMessage für menschenlesbare Fehlertexte
```c
char buffer[256];
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, buffer, sizeof(buffer), NULL);
printf("Fehler: %s\n", buffer);
```
## Hinweise
- Fehlercode ist thread-lokal gespeichert
- Immer direkt nach dem fehlerhaften Aufruf abfragen

31
doc/handle.md Normal file
View File

@ -0,0 +1,31 @@
# HANDLE Typreferenz (Windows API)
Ein `HANDLE` ist ein abstrakter Referenztyp in Windows, der auf Ressourcen verweist.
## Definition (aus `WinNT.h`)
```c
typedef void *HANDLE;
```
## Verwendung
Handles werden von vielen Windows-APIs zurückgegeben, z.B.:
- `CreateFile()` → HANDLE auf Datei
- `FindFirstFile()` → HANDLE für Suchkontext
- `CreateProcess()` → HANDLE auf Prozess
## Beispiel
```c
HANDLE hFind = FindFirstFile("*.txt", &find_data);
if (hFind == INVALID_HANDLE_VALUE) {
// Fehlerbehandlung
}
```
## Hinweise
- Handle müssen oft manuell freigegeben werden (`CloseHandle(h)`)
- Gültigkeitsprüfung oft mit `INVALID_HANDLE_VALUE`

39
doc/index.md Normal file
View File

@ -0,0 +1,39 @@
# 📚 Windows API Referenz CLI-Toolkit
Diese Dokumentation enthält kompakte technische Beschreibungen zentraler WinAPI-Strukturen und -Funktionen, wie sie im `treeScanner`-Projekt verwendet werden.
## 🔍 Inhaltsverzeichnis
### 💾 Dateisystem
- [WIN32_FIND_DATA](winapi_notes.md)
Struktur für Dateiinformationen bei `FindFirstFile`
- [MAX_PATH](max_path.md)
Einschränkungen und erweiterte Pfadlängen in Windows
### 🧠 Systemtypen
- [HANDLE](handle.md)
Allgemeiner Ressourcentyp unter Windows
- [FILETIME](filetime.md)
Zeitformat in 100-ns-Schritten seit 1601
### 🧵 Fehlerbehandlung
- [GetLastError](getlasterror.md)
Windows-Fehlercode auslesen und verstehen
### 🌐 Unicode & Konsole
- [SetConsoleOutputCP](setconsoleoutputcp.md)
Codepage für UTF-8-Ausgabe einstellen
- [Unicode vs ANSI](unicode_console.md)
Warum Konsolen Zeichen falsch darstellen und wie man es verhindert
---
## 🛠 Erweiterung geplant
- POSIX-Alternativen (`opendir`, `readdir`)
- `SYSTEMTIME`, `FormatMessageW`, `CloseHandle`
- Fehlercode-Tabelle + eigene Fehlerklasse für CLI-Tools

28
doc/max_path.md Normal file
View File

@ -0,0 +1,28 @@
# MAX_PATH Maximale Pfadlänge (Windows)
Windows beschränkt Pfade klassisch auf **260 Zeichen**. Diese Grenze ist durch den Wert `MAX_PATH` definiert.
## Definition
```c
#define MAX_PATH 260
```
## Beispiel
```c
char path[MAX_PATH];
snprintf(path, MAX_PATH, "C:\\Ordner\\Datei.txt");
```
## Überlange Pfade
Seit Windows 10 (ab Build 1607) kann man **lange Pfade bis 32.767 Zeichen** aktivieren:
- Voraussetzung: UTF-16-Pfade mit `\?\`-Präfix
- Beispiel: `\\?\C:\SehrLangerPfad\Datei.txt`
## Hinweise
- Ohne `\?\` gelten weiterhin 260 Zeichen
- Einige Windows-APIs und ältere Programme brechen bei langen Pfaden ab

32
doc/setconsoleoutputcp.md Normal file
View File

@ -0,0 +1,32 @@
# SetConsoleOutputCP Funktion (Windows API)
Mit `SetConsoleOutputCP()` kann die Ausgabe-Codepage der Konsole geändert werden z.B. für UTF-8.
## Definition
```c
BOOL SetConsoleOutputCP(UINT wCodePageID);
```
## Parameter
- `wCodePageID`: Ziel-Codepage, z.B. `65001` für UTF-8
## Beispiel
```c
#include <windows.h>
int main() {
SetConsoleOutputCP(65001); // Aktiviert UTF-8-Ausgabe
printf("📁 Datei
");
return 0;
}
```
## Hinweise
- Nur unter Windows verfügbar
- Gilt nur für das aktive Konsolenfenster
- Muss vor Unicode-Ausgabe erfolgen

37
doc/unicode_console.md Normal file
View File

@ -0,0 +1,37 @@
# Unicode vs ANSI in der Windows-Konsole
Standardmäßig nutzt die Windows-Konsole eine ANSI-Codepage (z.B. 850 oder 1252). Für echte Unicode-Zeichen wie 📁 oder ✓ ist das oft ungeeignet.
## Problem
- Ohne UTF-8: Unicode-Zeichen erscheinen als Kästchen oder Müll
- Ausgabe wie `📁` ergibt `ƒôü` oder ähnliches
## Lösung
### 1. UTF-8 aktivieren
```c
#include <windows.h>
SetConsoleOutputCP(65001); // Codepage 65001 = UTF-8
```
### 2. Kompiler-Flag setzen
```cmd
cl /utf-8 main.c ...
```
### 3. Terminal unterstützen lassen
- `cmd.exe`: nur begrenzt tauglich
- **Windows Terminal**: beste Wahl
- PowerShell (v7+) ebenfalls ok
### 4. Schriftart beachten
- Monospace + Unicode-fähig: `Cascadia Code`, `Segoe UI Emoji`, `Fira Code`
## Hinweis
- Auch Eingabe (`SetConsoleCP`) kann auf UTF-8 gesetzt werden, wird aber selten benötigt

51
doc/winapi_notes.md Normal file
View File

@ -0,0 +1,51 @@
# WIN32_FIND_DATA Strukturreferenz (Windows API)
Diese Struktur wird verwendet, um Dateiinformationen aus `FindFirstFile` und `FindNextFile` zu lesen.
## Definition (verkürzt)
```c
typedef struct _WIN32_FIND_DATA {
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
TCHAR cFileName[MAX_PATH];
TCHAR cAlternateFileName[14];
} WIN32_FIND_DATA;
```
## Wichtige Felder
| Feld | Typ | Beschreibung |
|-----------------------|----------|----------------------------------------------|
| `dwFileAttributes` | `DWORD` | Dateiattribute, z.B. `FILE_ATTRIBUTE_DIRECTORY` |
| `ftCreationTime` | `FILETIME` | Erstellungszeit |
| `ftLastWriteTime` | `FILETIME` | Letzte Änderung |
| `nFileSizeHigh` | `DWORD` | Dateigröße (oberer 32-Bit-Wert) |
| `nFileSizeLow` | `DWORD` | Dateigröße (unterer 32-Bit-Wert) |
| `cFileName` | `TCHAR[]`| Vollständiger Dateiname |
| `cAlternateFileName` | `TCHAR[]`| 8.3-Dateiname (DOS-kompatibel) |
## Beispiel
```c
WIN32_FIND_DATA find_data;
HANDLE hFind = FindFirstFile("C:\Beispiel\*", &find_data);
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
printf("📁 %s\n", find_data.cFileName);
} else {
printf("📄 %s\n", find_data.cFileName);
}
```
## Weitere Hinweise
- Wird ausschließlich unter Windows verwendet
- Maximaler Pfad ist `MAX_PATH` (260 Zeichen)
- Unicode-Unterstützung über `FindFirstFileW` möglich (für `WCHAR` statt `TCHAR`)
---

16
include/app.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef APP_H
#define APP_H
/**
* @brief Recursively scans the specified directory and prints an ASCII tree.
*
* This function lists the contents of a directory, using indentation to represent
* folder structure. Folders are printed with 📁 and files with 📄 icons.
* Currently implemented for Windows systems only.
*
* @param base_path The root directory to scan
* @param depth Current recursion depth, used for visual indentation
*/
void scan_directory(const char *base_path, int depth);
#endif

55
src/app.c Normal file
View File

@ -0,0 +1,55 @@
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <dirent.h> // for future POSIX support
#endif
#include "app.h"
/**
* @brief Implementation of recursive directory scanning using Windows API.
*
* Uses FindFirstFile and FindNextFile to enumerate folder contents.
* The current implementation supports only Windows platforms.
*
* @param base_path Root path to scan
* @param depth Recursion depth for indentation
*/
void scan_directory(const char *base_path, int depth) {
#ifdef _WIN32
WIN32_FIND_DATA find_data;
char search_path[MAX_PATH];
snprintf(search_path, MAX_PATH, "%s\\*", base_path);
HANDLE hFind = FindFirstFile(search_path, &find_data);
if (hFind == INVALID_HANDLE_VALUE) {
fprintf(stderr, "[ERROR] Zugriff auf %s fehlgeschlagen\n", base_path);
return;
}
do {
const char *name = find_data.cFileName;
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
continue;
for (int i = 0; i < depth; i++) printf(" ");
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
printf("📁 %s\n", name);
char sub_path[MAX_PATH];
snprintf(sub_path, MAX_PATH, "%s\\%s", base_path, name);
scan_directory(sub_path, depth + 1);
} else {
printf("📄 %s\n", name);
}
} while (FindNextFile(hFind, &find_data) != 0);
FindClose(hFind);
#else
fprintf(stderr, "[WARN] POSIX-Verzeichnisscan ist noch nicht implementiert\n");
#endif
}

28
src/main.c Normal file
View File

@ -0,0 +1,28 @@
#ifdef _WIN32
#include <windows.h>
#endif
#include <stdio.h>
#include "app.h"
/**
* @brief Entry point of the CLI tool.
*
* Initializes UTF-8 output on Windows, then calls scan_directory()
* with the provided argument or current directory.
*
* @param argc Number of arguments
* @param argv Array of argument strings
* @return int Exit status
*/
int main(int argc, char *argv[]) {
#ifdef _WIN32
SetConsoleOutputCP(CP_UTF8); // Enable Unicode output on Windows
#endif
printf("[INFO] CLI Tool gestartet\n");
const char *pfad = (argc > 1) ? argv[1] : ".";
scan_directory(pfad, 0);
return 0;
}