From 6d817ea87d684d666cebdec3e7c23147a9d836bb Mon Sep 17 00:00:00 2001 From: NotLe0n Date: Wed, 24 Apr 2024 21:48:03 +0200 Subject: [PATCH] Added Windows path functions to Duden/Pfade (#39) --- lib/stdlib/Duden/Pfade.ddp | 227 +++++++++++++--- lib/stdlib/include/winapi-path.h | 12 + lib/stdlib/source/path.c | 39 +++ lib/stdlib/source/winapi-path.c | 332 +++++++++++++++++++++++ tests/testdata/stdlib/Pfade/Pfade.ddp | 204 ++++++++++---- tests/testdata/stdlib/Pfade/expected.txt | 74 +++++ 6 files changed, 798 insertions(+), 90 deletions(-) create mode 100644 lib/stdlib/include/winapi-path.h create mode 100644 lib/stdlib/source/path.c create mode 100644 lib/stdlib/source/winapi-path.c diff --git a/lib/stdlib/Duden/Pfade.ddp b/lib/stdlib/Duden/Pfade.ddp index c4d7b2a6..9e65f5ce 100644 --- a/lib/stdlib/Duden/Pfade.ddp +++ b/lib/stdlib/Duden/Pfade.ddp @@ -1,11 +1,11 @@ -[ - Pfad Manipulationsfunktionen. NUR FÜR UNIX! -] - - Binde "Duden/Texte" ein. +Binde "Duden/Zeichen" ein. Binde Betriebssystem und Arbeitsverzeichnis aus "Duden/Laufzeit" ein. +[ + UNIX Funktionen +] + [ Gibt den Pfad-Trennzeichen, der dem Betriebssystem entspricht zurück. Auf Linux: '/' @@ -20,12 +20,14 @@ Und kann so benutzt werden: "das Pfad-Trennzeichen" [ - Gibt zurück ob der gegebene UNIX Pfad ein absoluter oder relativer Pfad ist + Gibt zurück ob der gegebene UNIX Pfad ein absoluter oder relativer Pfad ist. + Der Rückgabewert ist wahr wenn der erste Buchstabe des gegebenen Textes ein '/' ist. ] -Die öffentliche Funktion Ist_Absolut mit dem Parameter t vom Typ Text, gibt einen Wahrheitswert zurück, macht: - Gib wahr, wenn '/' am Anfang von t steht zurück. +Die öffentliche Funktion UNIX_Ist_Absolut mit dem Parameter t vom Typ Text, gibt einen Wahrheitswert zurück, macht: + Wenn die Länge von t gleich 0 ist, gib falsch zurück. + Gib wahr, wenn (t an der Stelle 1) gleich '/' ist zurück. Und kann so benutzt werden: - " ein Absoluter Pfad ist" + " ein absoluter UNIX Pfad ist" [ Säubert/Normalisiert einen UNIX Pfad: @@ -40,7 +42,7 @@ Und kann so benutzt werden: Entspricht Go's path.clean funktion https://pkg.go.dev/path#Clean ] -Die öffentliche Funktion Säubern mit dem Parameter t vom Typ Text, gibt einen Text zurück, macht: +Die öffentliche Funktion UNIX_Säubern mit dem Parameter t vom Typ Text, gibt einen Text zurück, macht: Wenn t gleich "" ist, gib "." zurück. Der Wahrheitswert rooted ist wahr, wenn t an der Stelle 1 gleich '/' ist. Die Zahl n ist die Länge von t. @@ -88,17 +90,17 @@ Die öffentliche Funktion Säubern mit dem Parameter t vom Typ Text, gibt einen Wenn path leer ist, speichere "." in path. Gib path zurück. Und kann so benutzt werden: - "der Pfad gesäubert" + "der UNIX Pfad gesäubert" [ Verbindet zwei UNIX Pfade mit einem '/' und säubert zuletzt. ] -Die öffentliche Funktion Verbinden mit den Parametern a und b vom Typ Text und Text, gibt einen Text zurück, macht: +Die öffentliche Funktion UNIX_Verbinden mit den Parametern a und b vom Typ Text und Text, gibt einen Text zurück, macht: Wenn a leer ist, gib b zurück. Wenn b leer ist, gib a zurück. - Gib der Pfad (a verkettet mit '/' verkettet mit b) gesäubert zurück. + Gib der UNIX Pfad (a verkettet mit '/' verkettet mit b) gesäubert zurück. Und kann so benutzt werden: - "die Pfade und verbunden" + "die UNIX Pfade und verbunden" [ Pfade Terminologie: @@ -113,17 +115,17 @@ Und kann so benutzt werden: ] [ - Nimmt einen Relativen Pfad t und gibt den vollständigen absoluten Pfad zurück. + Nimmt einen Relativen UNIX Pfad t und gibt den vollständigen absoluten Pfad zurück. ] -Die öffentliche Funktion VollständigerPfad mit dem Parameter t vom Typ Text, gibt einen Text zurück, macht: +Die öffentliche Funktion UNIX_VollständigerPfad mit dem Parameter t vom Typ Text, gibt einen Text zurück, macht: Der Text cwd ist der Arbeitsverzeichnis. - Gib die Pfade cwd und t verbunden zurück. + Gib die UNIX Pfade cwd und t verbunden zurück. Und kann so benutzt werden: - "den absoluten Pfad zu ", - "der absoluten Pfad zu " + "den absoluten UNIX Pfad zu ", + "der absoluten UNIX Pfad zu " [ - Gibt den Pfad ohne das letze Element zurück. + Gibt den UNIX Pfad ohne das letze Element zurück. Falls der Pfad leer ist, wird ein "." zurück gegeben. Falls der Pfad nur aus "/" gefolg von nicht-"/" Zeichen, wird "/" zurückgegeben. @@ -137,7 +139,7 @@ Und kann so benutzt werden: f(".") = "." f("") = "." ] -Die öffentliche Funktion Ordnerpfad mit dem Parameter t vom Typ Text, gibt einen Text zurück, macht: +Die öffentliche Funktion UNIX_Ordnerpfad mit dem Parameter t vom Typ Text, gibt einen Text zurück, macht: Die Zahl i ist die Länge von t. Solange i größer als 0 ist, mache: @@ -150,11 +152,11 @@ Die öffentliche Funktion Ordnerpfad mit dem Parameter t vom Typ Text, gibt eine Verringere i um 1. Gib "." zurück. Und kann so benutzt werden: - "den Ordnerpfad von ", - "der Ordnerpfad von " + "den UNIX Ordnerpfad von ", + "der UNIX Ordnerpfad von " [ - Gibt den letzten Element eines Pfades zurück. Falls der Pfad leer ist, wird "." ausgegeben. + Gibt den letzten Element eines UNIX Pfades zurück. Falls der Pfad leer ist, wird "." ausgegeben. f("/a/b/c/d.png") = "d.png" f("/a/b/c/d") = "d" @@ -166,7 +168,7 @@ Und kann so benutzt werden: f("..") = ".." f("") = "." ] -Die öffentliche Funktion Basisname mit dem Parameter t vom Typ Text, gibt einen Text zurück, macht: +Die öffentliche Funktion UNIX_Basisname mit dem Parameter t vom Typ Text, gibt einen Text zurück, macht: Der Text t2 ist (t mit allen '/' danach entfernt). Die Zahl i ist die Länge von t2. Wenn t2 gleich "" ist, gib "." zurück. @@ -175,11 +177,11 @@ Die öffentliche Funktion Basisname mit dem Parameter t vom Typ Text, gibt einen Verringere i um 1. Gib t2 ab dem (i plus 1). Element zurück. Und kann so benutzt werden: - "den Basisnamen von ", - "der Basisname von " + "den UNIX Basisnamen von ", + "der UNIX Basisname von " [ - Gibt den Dateinamen einer Datei zurück. Wenn der Pfad nicht im Format von '*/*.*' ist wird ein leerer Text zurück gegeben. + Gibt den Dateinamen einer Datei zurück. Wenn der UNIX Pfad nicht im Format von '*/*.*' ist wird ein leerer Text zurück gegeben. f("/a/b/c/test.txt") = "test" f("/a/b/c/test.txt.exe") = "test" @@ -192,7 +194,7 @@ Und kann so benutzt werden: f("noext") = "" f("") = "" ] -Die öffentliche Funktion Datei_Name mit dem Parameter t vom Typ Text, gibt einen Text zurück, macht: +Die öffentliche Funktion UNIX_Datei_Name mit dem Parameter t vom Typ Text, gibt einen Text zurück, macht: Die Zahl i ist die Länge von t. Die Zahl ende ist -1. Solange i größer als 0 ist, mache: @@ -202,12 +204,11 @@ Die öffentliche Funktion Datei_Name mit dem Parameter t vom Typ Text, gibt eine Wenn ende kleiner als 1 ist, gib "" zurück. Gib t im Bereich von i plus 1 bis ende zurück. Und kann so benutzt werden: - "den Dateinamen von ", - "der Dateiname von " + "den UNIX Dateinamen von ", + "der UNIX Dateiname von " [ - Gibt die Erweiterung einer Datei zurück. Wenn der Pfad eines Ordners gegeben wurde, die Datei bei dem Pfad keine Erweiterung hat - oder der Parameter t leer ist, wird einen leeren Text zurück gegeben. + Gibt die Erweiterung einer Datei zurück. Wenn der UNIX Pfad t ein Ordner ist oder leer ist, wird einen leeren Text zurück gegeben. f("/a/b/c/bar.css") = "css" f("/a/b/c/foo.tar.gz") = "tar.gz" @@ -219,7 +220,7 @@ Und kann so benutzt werden: f("noext") = "" f("") = "" ] -Die öffentliche Funktion Erweiterung mit dem Parameter t vom Typ Text, gibt einen Text zurück, macht: +Die öffentliche Funktion UNIX_Erweiterung mit dem Parameter t vom Typ Text, gibt einen Text zurück, macht: Die Zahl i ist die Länge von t. Die Zahl extStart ist i. Solange i größer als 0 ist, mache: @@ -229,4 +230,160 @@ Die öffentliche Funktion Erweiterung mit dem Parameter t vom Typ Text, gibt ein Wenn extStart größer als, oder die Länge von t ist, gib "" zurück. Gib t ab dem extStart. Element zurück. Und kann so benutzt werden: - "die Erweiterung der Datei bei " \ No newline at end of file + "die UNIX Erweiterung der Datei bei " + + +[ + Windows Funktionen +] + + +[ + Gibt wahr zurück wenn der gegebene Windows Pfad mit einem "\" anfängt oder der zweite Buchstabe ein Doppelpunkt ist ("C:"). +] +Die öffentliche Funktion Windows_Ist_Absolut mit dem Parameter t vom Typ Text, gibt einen Wahrheitswert zurück, macht: + Wenn t gleich "" ist, gib falsch zurück. + Wenn t an der Stelle 1 gleich '\\' ist, gib wahr zurück. [ "\Users\admin\" ] + Gib wahr, wenn die Länge von t größer als, oder 2 ist und (t an der Stelle 1) ein lateinischer Buchstabe ist und t an der Stelle 2 gleich ':' ist zurück. [ "C:\Users\admin\" ] +Und kann so benutzt werden: + " ein absoluter Windows Pfad ist" + +[ + Säubert/Normalisiert einen gegebenen Windows Pfad. Entfernt keine doppelten Schrägstrichen (\\)! + + f("C:\\Users\\admin") = "C:\Users\admin" + f("C:\\Users\\admin\\") = "C:\Users\admin\" + f("C:\\Users\\admin\\..") = "C:\Users" + f("C:\\Users\\admin\\..\\") = "C:\Users\" + f("C:\\Users\\admin\\.") = "C:\Users\admin" + f("C:\\Users\\admin\\.\\") = "C:\Users\admin\" + f("C:\\Users\\..\\admin\\.") = "C:\admin" + f("C:\\Users\\\\admin") = "C:\Users\\admin" + f("C:\\..") = "C:\" + f("C:") = "C:\" + f("..") = "\" + f(".") = "\" + f("") = "\" +] +Die öffentliche Funktion Windows_Saeubern mit dem Parameter t vom Typ Text, gibt einen Text zurück, +ist in "libddpstdlib.a" definiert +Und kann so benutzt werden: + "der Windows Pfad gesäubert" + +[ + Verbindet zwei Windows Pfade und säubert zuletzt. +] +Die öffentliche Funktion Windows_Pfad_Verbinden mit den Parametern a und b vom Typ Text und Text, gibt einen Text zurück, +ist in "libddpstdlib.a" definiert +Und kann so benutzt werden: + "die Windows Pfade und verbunden" + +[ + Pfade Terminologie: + + Beispiel: "C:\Users\admin\Documents\test.tar.gz" + + Laufwerkbuchstabe: 'C' + Vollständiger Pfad: "C:\Users\admin\Documents\test.tar.gz" + Ordnerpfad: "C:\Users\admin\Documents" + Basisname: "test.tar.gz" + Dateiname: "test" + Erweiterung: "tar.gz" +] + +[ + Gibt den Laufwerkbuchstaben des gegebenen Windows Pfads zurück. Wenn keiner existiert wird ' ' zurück gegeben. + Falls der Laufwerkbuchstaben kein Buchstabe zwischen a-Z ist wird auch ' ' zurückgegeben. +] +Die öffentliche Funktion Windows_Laufwerkbuchstabe mit dem Parameter t vom Typ Text, gibt einen Buchstaben zurück, macht: + Wenn die Länge von t kleiner als 2 ist, gib ' ' zurück. + Wenn t an der Stelle 2 ungleich ':' ist, gib ' ' zurück. + Wenn nicht (t an der Stelle 1) ein lateinischer Buchstabe ist, gib ' ' zurück. + Gib t an der Stelle 1 zurück. +Und kann so benutzt werden: + "der Laufwerkbuchstabe von ", + "den Laufwerkbuchstaben von " + +[ + Nimmt einen Relativen Windows Pfad t und gibt den vollständigen absoluten Pfad zurück. +] +Die öffentliche Funktion Windows_VollständigerPfad mit dem Parameter t vom Typ Text, gibt einen Text zurück, macht: + Der Text cwd ist der Arbeitsverzeichnis. + Gib die Windows Pfade cwd und t verbunden zurück. +Und kann so benutzt werden: + "den absoluten Windows Pfad zu ", + "der absoluten Windows Pfad zu " + +[ + Gibt den Windows Pfad ohne das letze Element zurück. + Falls der Pfad leer ist, wird ein "." zurück gegeben. + Falls der Pfad nur aus "C:\" gefolgt von nicht-"/" oder nicht-"\" Zeichen, wird "C:\" zurückgegeben. + Falls der Pfad nur aus "\" oder "/" gefolgt von nicht-"/" oder nicht-"\" Zeichen, wird "\" zurückgegeben. +] +Die öffentliche Funktion Windows_Ordnerpfad mit dem Parameter t vom Typ Text, gibt einen Text zurück, macht: + Die Zahl i ist die Länge von t. + + Solange i größer als 0 ist, mache: + Wenn t an der Stelle i gleich '\\' ist oder t an der Stelle i gleich '/' ist, dann: + Der Text dir ist t bis zum i. Element. + Entferne alle '\\' nach dir. + Wenn die Länge von dir gleich 0 ist, gib "\\" zurück. [ "\abc" -> "\" ] + Wenn ':' am Ende von dir steht, gib dir verkettet mit '\\' zurück. [ "C:\abc" -> "C:\" ] + + Gib dir zurück. + Verringere i um 1. + Gib "." zurück. +Und kann so benutzt werden: + "den Windows Ordnerpfad von ", + "der Windows Ordnerpfad von " + +[ + Gibt das letzte Element des gegebenen Windows Pfads zurück. +] +Die öffentliche Funktion Windows_Basisname mit dem Parameter t vom Typ Text, gibt einen Text zurück, macht: + Die Zahl ende ist die Länge von t. + Wenn ende gleich 0 ist, gib "." zurück. + Solange t an der Stelle ende gleich '\\' ist oder t an der Stelle ende gleich '/' ist, verringere ende um 1. + + Die Zahl i ist ende. + Solange i größer als 0 ist, mache: + Der Buchstabe curr ist t an der Stelle i. + Wenn (curr gleich '\\' ist oder curr gleich '/' ist oder curr gleich ':' ist), verlasse die Schleife. + Verringere i um 1. + Gib t im Bereich von (i plus 1) bis ende zurück. +Und kann so benutzt werden: + "den Windows Basisnamen von ", + "der Windows Basisname von " + +[ + Gibt den Dateinamen einer Datei zurück. Wenn der Windows Pfad nicht im Format von '*\*.*', '*\*.*' oder '*:*.*' ist wird ein leerer Text zurück gegeben. +] +Die öffentliche Funktion Windows_Datei_Name mit dem Parameter t vom Typ Text, gibt einen Text zurück, macht: + Die Zahl i ist die Länge von t. + Die Zahl ende ist -1. + Solange i größer als 0 ist, mache: + Der Buchstabe curr ist t an der Stelle i. + Wenn curr gleich '.' ist, speichere i minus 1 in ende. + Wenn curr gleich '\\' ist oder curr gleich '/' ist oder curr gleich ':' ist, verlasse die Schleife. + Verringere i um 1. + Wenn ende kleiner als 1 ist, gib "" zurück. + Gib t im Bereich von i plus 1 bis ende zurück. +Und kann so benutzt werden: + "den Windows Dateinamen von ", + "der Windows Dateiname von " + +[ + Gibt die Erweiterung einer Datei zurück. Wenn der Windows Pfad t ein Ordner ist oder leer ist, wird einen leeren Text zurück gegeben. +] +Die öffentliche Funktion Windows_Erweiterung mit dem Parameter t vom Typ Text, gibt einen Text zurück, macht: + Die Zahl i ist die Länge von t. + Die Zahl extStart ist i. + Solange i größer als 0 ist, mache: + Der Buchstabe curr ist t an der Stelle i. + Wenn curr gleich '.' ist, speichere i plus 1 in extStart. + Wenn curr gleich '\\' ist oder curr gleich '/' ist oder curr gleich ':' ist, verlasse die Schleife. + Verringere i um 1. + Wenn extStart größer als, oder die Länge von t ist, gib "" zurück. + Gib t ab dem extStart. Element zurück. +Und kann so benutzt werden: + "die Windows Erweiterung der Datei bei " \ No newline at end of file diff --git a/lib/stdlib/include/winapi-path.h b/lib/stdlib/include/winapi-path.h new file mode 100644 index 00000000..70069a40 --- /dev/null +++ b/lib/stdlib/include/winapi-path.h @@ -0,0 +1,12 @@ +#ifndef WINAPI_PATH_H +#define WINAPI_PATH_H + +#define MAX_PATH 260 +#include "ddptypes.h" +#include + + +bool PathCanonicalize(char *buffer, const char *path); +char *PathCombine(char *lpszDest, const char *lpszDir, const char *lpszFile); + +#endif // WINAPI_PATH_H diff --git a/lib/stdlib/source/path.c b/lib/stdlib/source/path.c new file mode 100644 index 00000000..7891d969 --- /dev/null +++ b/lib/stdlib/source/path.c @@ -0,0 +1,39 @@ +#include "ddpmemory.h" +#include "ddptypes.h" +#include "winapi-path.h" +#include +#include + + +void Windows_Saeubern(ddpstring *ret, ddpstring *path) { + char cleaned[MAX_PATH]; + if (!PathCanonicalize(cleaned, path->str)) { + *ret = DDP_EMPTY_STRING; + ret->str = DDP_ALLOCATE(char, 1); + ret->str[0] = '\0'; + ret->cap = 1; + return; + } + int len = strlen(cleaned) + 1; + char *str = DDP_ALLOCATE(char, len); + memcpy(str, cleaned, len); + ret->str = str; + ret->cap = len; +} + +void Windows_Pfad_Verbinden(ddpstring *ret, ddpstring *a, ddpstring *b) { + char joined[MAX_PATH]; + if (!PathCombine(joined, a->str, b->str)) { + *ret = DDP_EMPTY_STRING; + ret->str = DDP_ALLOCATE(char, 1); + ret->str[0] = '\0'; + ret->cap = 1; + return; + } + + int len = strlen(joined) + 1; + char *str = DDP_ALLOCATE(char, len); + memcpy(str, joined, len); + ret->str = str; + ret->cap = len; +} diff --git a/lib/stdlib/source/winapi-path.c b/lib/stdlib/source/winapi-path.c new file mode 100644 index 00000000..d50de9df --- /dev/null +++ b/lib/stdlib/source/winapi-path.c @@ -0,0 +1,332 @@ +#include "winapi-path.h" + +/* + * Path Functions + * + * Copyright 1999, 2000 Juergen Schmied + * Copyright 2001, 2002 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// Adapted slightly to bring it more inline with the unix api + +/* + PathCanonicalize +*/ + +char *CharNext(const char *ptr) { + if (!*ptr) { + return (char *)ptr; + } + //if (IsDBCSLeadByte(ptr[0]) && ptr[1]) return (char*)(ptr + 2); + return (char *)(ptr + 1); +} + +int PathIsUNCServerShare(const char *path) { + bool seen_slash = 0; + + if (!path || *path++ != '\\' || *path++ != '\\') { + return false; + } + + while (*path) { + if (*path == '\\') { + if (seen_slash) { + return false; + } + seen_slash = true; + } + + path = CharNext(path); + } + + return seen_slash; +} + +bool PathCanonicalize(char *buffer, const char *path) { + const char *src = path; + char *dst = buffer; + + if (dst) { + *dst = '\0'; + } + + if (!dst || !path) { + return 0; + } + + if (!*path) { + *buffer++ = '\\'; + *buffer = '\0'; + return 1; + } + + // Copy path root + if (*src == '\\') { + *dst++ = *src++; + } else if (*src && src[1] == ':') { + /* X:\ */ + *dst++ = *src++; + *dst++ = *src++; + if (*src == '\\') { + *dst++ = *src++; + } + } + + // Canonicalize the rest of the path + while (*src) { + if (*src != '.') { + *dst++ = *src++; + continue; + } + + // Handle *\. + if (src[-1] == '\\' && src[1] == '\0') { + dst--; /* Remove \ */ + src++; /* Skip . */ + } + // Handle *.\ or .\* or *\.\* or *:.\* + else if (src[1] == '\\' && (src == path || src[-1] == '\\' || src[-1] == ':')) { + src += 2; /* Skip .\ */ + } + // Handle *\..* + else if (src[1] == '.' && dst != buffer && dst[-1] == '\\') { // + /* + \.. backs up a directory, over the root if it has no \ following X:. + * .. is ignored if it would remove a UNC server name or initial \\ + */ + if (dst != buffer) { + *dst = '\0'; // Allow PathIsUNCServerShareA test on lpszBuf + if (dst > buffer + 1 && dst[-1] == '\\' && (dst[-2] != '\\' || dst > buffer + 2)) { + if (dst[-2] == ':' && (dst > buffer + 3 || dst[-3] == ':')) { + dst -= 2; + while (dst > buffer && *dst != '\\') { + dst--; + } + + if (*dst == '\\') { + dst++; /* Reset to last '\' */ + } else { + dst = buffer; // Start path again from new root + } + } else if (dst[-2] != ':' && !PathIsUNCServerShare(buffer)) { + dst -= 2; + } + } + while (dst > buffer && *dst != '\\') { + dst--; + } + if (dst == buffer) { + *dst++ = '\\'; + src++; + } + } + src += 2; // Skip .. in src path + } + // start of path + else if (dst == buffer) { + // Handle .. + if (src[1] == '.') { + src++; + } + // Handle . + else if (src[1] == '\0') { + *dst++ = '\\'; + src++; + } + } else { + *dst++ = *src++; + } + } + + // Append \ to naked drive specs + if (dst - buffer == 2 && dst[-1] == ':') { + *dst++ = '\\'; + } + + *dst++ = '\0'; + return 1; +} + +/* + PathCombine +*/ + +char *lstrcpynA(char *lpString1, const char *lpString2, int iMaxLength) { + char *d = lpString1; + const char *s = lpString2; + unsigned int count = iMaxLength; + char *Ret = NULL; + + while ((count > 1) && *s) { + count--; + *d++ = *s++; + } + + if (count) { + *d = 0; + } + + Ret = lpString1; + + return Ret; +} + +char *PathAddBackslashA(char *lpszPath) { + size_t iLen; + char *prev = lpszPath; + + if (!lpszPath || (iLen = strlen(lpszPath)) >= MAX_PATH) { + return NULL; + } + + if (iLen) { + do { + lpszPath = CharNext(prev); + if (*lpszPath) { + prev = lpszPath; + } + } while (*lpszPath); + + if (*prev != '\\') { + *lpszPath++ = '\\'; + *lpszPath = '\0'; + } + } + return lpszPath; +} + +bool PathIsRootA(const char *lpszPath) { + + if (lpszPath && *lpszPath) { + if (*lpszPath == '\\') { + if (!lpszPath[1]) { + return true; /* \ */ + } else if (lpszPath[1] == '\\') { + bool bSeenSlash = false; + lpszPath += 2; + + /* Check for UNC root path */ + while (*lpszPath) { + if (*lpszPath == '\\') { + if (bSeenSlash) { + return false; + } + bSeenSlash = true; + } + lpszPath = CharNext(lpszPath); + } + return true; + } + } else if (lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0') { + return true; /* X:\ */ + } + } + return false; +} + +bool PathRemoveFileSpecA(char *lpszPath) { + char *lpszFileSpec = lpszPath; + bool bModified = false; + + if (lpszPath) { + /* Skip directory or UNC path */ + if (*lpszPath == '\\') { + lpszFileSpec = ++lpszPath; + } + if (*lpszPath == '\\') { + lpszFileSpec = ++lpszPath; + } + + while (*lpszPath) { + if (*lpszPath == '\\') { + lpszFileSpec = lpszPath; /* Skip dir */ + } else if (*lpszPath == ':') { + lpszFileSpec = ++lpszPath; /* Skip drive */ + if (*lpszPath == '\\') { + lpszFileSpec++; + } + } + if (!(lpszPath = CharNext(lpszPath))) { + break; + } + } + + if (*lpszFileSpec) { + *lpszFileSpec = '\0'; + bModified = true; + } + } + return bModified; +} + +bool PathStripToRootA(char *lpszPath) { + + if (!lpszPath) { + return false; + } + while (!PathIsRootA(lpszPath)) { + if (!PathRemoveFileSpecA(lpszPath)) { + return false; + } + } + return true; +} + +char *PathCombine(char *lpszDest, const char *lpszDir, const char *lpszFile) { + char szTemp[MAX_PATH]; + bool bUseBoth = false, bStrip = false; + + /* Invalid parameters */ + if (!lpszDest) { + return NULL; + } + if (!lpszDir && !lpszFile) { + lpszDest[0] = 0; + return NULL; + } + + if ((!lpszFile || !*lpszFile) && lpszDir) { + /* Use dir only */ + lstrcpynA(szTemp, lpszDir, MAX_PATH); + } else if (!lpszDir || !*lpszDir || *lpszFile == '\\' || (*lpszFile && lpszFile[1] == ':')) { + if (!lpszDir || !*lpszDir || *lpszFile != '\\' || (lpszFile && (lpszFile[0] == '\\') && (lpszFile[1] == '\\'))) { + /* Use file only */ + lstrcpynA(szTemp, lpszFile, MAX_PATH); + } else { + bUseBoth = true; + bStrip = true; + } + } else { + bUseBoth = true; + } + + if (bUseBoth) { + lstrcpynA(szTemp, lpszDir, MAX_PATH); + if (bStrip) { + PathStripToRootA(szTemp); + lpszFile++; /* Skip '\' */ + } + if (!PathAddBackslashA(szTemp) || strlen(szTemp) + strlen(lpszFile) >= MAX_PATH) { + lpszDest[0] = 0; + return NULL; + } + strcat(szTemp, lpszFile); + } + + PathCanonicalize(lpszDest, szTemp); + return lpszDest; +} diff --git a/tests/testdata/stdlib/Pfade/Pfade.ddp b/tests/testdata/stdlib/Pfade/Pfade.ddp index dfe6479e..cb6ca916 100644 --- a/tests/testdata/stdlib/Pfade/Pfade.ddp +++ b/tests/testdata/stdlib/Pfade/Pfade.ddp @@ -1,71 +1,165 @@ Binde "Duden/Pfade" ein. Binde "Duden/Ausgabe" ein. +[UNIX TESTS] + [ OrdnerPfad Tests ] -Schreibe (den Ordnerpfad von "/a/b/c") auf eine Zeile. -Schreibe (den Ordnerpfad von "a/b/c") auf eine Zeile. -Schreibe (den Ordnerpfad von "/a/") auf eine Zeile. -Schreibe (den Ordnerpfad von "a/") auf eine Zeile. -Schreibe (den Ordnerpfad von "a") auf eine Zeile. -Schreibe (den Ordnerpfad von "/") auf eine Zeile. -Schreibe (den Ordnerpfad von "..") auf eine Zeile. -Schreibe (den Ordnerpfad von ".") auf eine Zeile. -Schreibe (den Ordnerpfad von "") auf eine Zeile. +Schreibe (den UNIX Ordnerpfad von "/a/b/c") auf eine Zeile. +Schreibe (den UNIX Ordnerpfad von "a/b/c") auf eine Zeile. +Schreibe (den UNIX Ordnerpfad von "/a/") auf eine Zeile. +Schreibe (den UNIX Ordnerpfad von "a/") auf eine Zeile. +Schreibe (den UNIX Ordnerpfad von "a") auf eine Zeile. +Schreibe (den UNIX Ordnerpfad von "/") auf eine Zeile. +Schreibe (den UNIX Ordnerpfad von "..") auf eine Zeile. +Schreibe (den UNIX Ordnerpfad von ".") auf eine Zeile. +Schreibe (den UNIX Ordnerpfad von "") auf eine Zeile. [ Basisname Tests ] -Schreibe (den Basisnamen von "/a/b/c/d.png") auf eine Zeile. -Schreibe (den Basisnamen von "/a/b/c/d") auf eine Zeile. -Schreibe (den Basisnamen von "/a/b/c/") auf eine Zeile. -Schreibe (den Basisnamen von "/a/b/c///") auf eine Zeile. -Schreibe (den Basisnamen von "./b") auf eine Zeile. -Schreibe (den Basisnamen von "hi.txt") auf eine Zeile. -Schreibe (den Basisnamen von ".") auf eine Zeile. -Schreibe (den Basisnamen von "..") auf eine Zeile. -Schreibe (den Basisnamen von "") auf eine Zeile. +Schreibe (den UNIX Basisnamen von "/a/b/c/d.png") auf eine Zeile. +Schreibe (den UNIX Basisnamen von "/a/b/c/d") auf eine Zeile. +Schreibe (den UNIX Basisnamen von "/a/b/c/") auf eine Zeile. +Schreibe (den UNIX Basisnamen von "/a/b/c///") auf eine Zeile. +Schreibe (den UNIX Basisnamen von "./b") auf eine Zeile. +Schreibe (den UNIX Basisnamen von "hi.txt") auf eine Zeile. +Schreibe (den UNIX Basisnamen von ".") auf eine Zeile. +Schreibe (den UNIX Basisnamen von "..") auf eine Zeile. +Schreibe (den UNIX Basisnamen von "") auf eine Zeile. [ DateiName Tests ] -Schreibe (den Dateinamen von "/a/b/c/test.txt") auf eine Zeile. -Schreibe (den Dateinamen von "/a/b/c/test.txt.exe") auf eine Zeile. -Schreibe (den Dateinamen von "test.exe") auf eine Zeile. -Schreibe (den Dateinamen von "/a/b/c/") auf eine Zeile. -Schreibe (den Dateinamen von "/a/b/c") auf eine Zeile. -Schreibe (den Dateinamen von "/") auf eine Zeile. -Schreibe (den Dateinamen von ".") auf eine Zeile. -Schreibe (den Dateinamen von "..") auf eine Zeile. -Schreibe (den Dateinamen von "noext") auf eine Zeile. -Schreibe (den Dateinamen von "") auf eine Zeile. +Schreibe (den UNIX Dateinamen von "/a/b/c/test.txt") auf eine Zeile. +Schreibe (den UNIX Dateinamen von "/a/b/c/test.txt.exe") auf eine Zeile. +Schreibe (den UNIX Dateinamen von "test.exe") auf eine Zeile. +Schreibe (den UNIX Dateinamen von "/a/b/c/") auf eine Zeile. +Schreibe (den UNIX Dateinamen von "/a/b/c") auf eine Zeile. +Schreibe (den UNIX Dateinamen von "/") auf eine Zeile. +Schreibe (den UNIX Dateinamen von ".") auf eine Zeile. +Schreibe (den UNIX Dateinamen von "..") auf eine Zeile. +Schreibe (den UNIX Dateinamen von "noext") auf eine Zeile. +Schreibe (den UNIX Dateinamen von "") auf eine Zeile. [ Erweiterung Tests ] -Schreibe (die Erweiterung der Datei bei "/a/b/c/bar.css") auf eine Zeile. -Schreibe (die Erweiterung der Datei bei "/a/b/c/foo.tar.gz") auf eine Zeile. -Schreibe (die Erweiterung der Datei bei "bar.css") auf eine Zeile. -Schreibe (die Erweiterung der Datei bei "/a/b.trap/c/noext") auf eine Zeile. -Schreibe (die Erweiterung der Datei bei "/") auf eine Zeile. -Schreibe (die Erweiterung der Datei bei ".") auf eine Zeile. -Schreibe (die Erweiterung der Datei bei "..") auf eine Zeile. -Schreibe (die Erweiterung der Datei bei "noext") auf eine Zeile. -Schreibe (die Erweiterung der Datei bei "") auf eine Zeile. +Schreibe (die UNIX Erweiterung der Datei bei "/a/b/c/bar.css") auf eine Zeile. +Schreibe (die UNIX Erweiterung der Datei bei "/a/b/c/foo.tar.gz") auf eine Zeile. +Schreibe (die UNIX Erweiterung der Datei bei "bar.css") auf eine Zeile. +Schreibe (die UNIX Erweiterung der Datei bei "/a/b.trap/c/noext") auf eine Zeile. +Schreibe (die UNIX Erweiterung der Datei bei "/") auf eine Zeile. +Schreibe (die UNIX Erweiterung der Datei bei ".") auf eine Zeile. +Schreibe (die UNIX Erweiterung der Datei bei "..") auf eine Zeile. +Schreibe (die UNIX Erweiterung der Datei bei "noext") auf eine Zeile. +Schreibe (die UNIX Erweiterung der Datei bei "") auf eine Zeile. [ Säubern Tests ] -Schreibe (der Pfad "a/c" gesäubert) auf eine Zeile. -Schreibe (der Pfad "a//c" gesäubert) auf eine Zeile. -Schreibe (der Pfad "a/c/." gesäubert) auf eine Zeile. -Schreibe (der Pfad "a/c/b/.." gesäubert) auf eine Zeile. -Schreibe (der Pfad "/../a/c" gesäubert) auf eine Zeile. -Schreibe (der Pfad "/../a/b/../././/c" gesäubert) auf eine Zeile. -Schreibe (der Pfad "a/b/../../../xyz" gesäubert) auf eine Zeile. -Schreibe (der Pfad ".." gesäubert) auf eine Zeile. -Schreibe (der Pfad "" gesäubert) auf eine Zeile. +Schreibe (der UNIX Pfad "a/c" gesäubert) auf eine Zeile. +Schreibe (der UNIX Pfad "a//c" gesäubert) auf eine Zeile. +Schreibe (der UNIX Pfad "a/c/." gesäubert) auf eine Zeile. +Schreibe (der UNIX Pfad "a/c/b/.." gesäubert) auf eine Zeile. +Schreibe (der UNIX Pfad "/../a/c" gesäubert) auf eine Zeile. +Schreibe (der UNIX Pfad "/../a/b/../././/c" gesäubert) auf eine Zeile. +Schreibe (der UNIX Pfad "a/b/../../../xyz" gesäubert) auf eine Zeile. +Schreibe (der UNIX Pfad ".." gesäubert) auf eine Zeile. +Schreibe (der UNIX Pfad "" gesäubert) auf eine Zeile. [ IstAbsout Tests ] -Schreibe ("/a/b" ein Absoluter Pfad ist) auf eine Zeile. -Schreibe ("a/b" ein Absoluter Pfad ist) auf eine Zeile. -Schreibe ("" ein Absoluter Pfad ist) auf eine Zeile. +Schreibe ("/a/b" ein absoluter UNIX Pfad ist) auf eine Zeile. +Schreibe ("a/b" ein absoluter UNIX Pfad ist) auf eine Zeile. +Schreibe ("" ein absoluter UNIX Pfad ist) auf eine Zeile. [ Verbinden Tests ] -Schreibe (die Pfade "a" und "b/c" verbunden) auf eine Zeile. -Schreibe (die Pfade "a/b" und "c" verbunden) auf eine Zeile. -Schreibe (die Pfade "" und "a/b" verbunden) auf eine Zeile. -Schreibe (die Pfade "a/b" und "" verbunden) auf eine Zeile. -Schreibe (die Pfade "" und "" verbunden) auf eine Zeile. -Schreibe (die Pfade "a/b" und "../../../xyz" verbunden) auf eine Zeile. \ No newline at end of file +Schreibe (die UNIX Pfade "a" und "b/c" verbunden) auf eine Zeile. +Schreibe (die UNIX Pfade "a/b" und "c" verbunden) auf eine Zeile. +Schreibe (die UNIX Pfade "" und "a/b" verbunden) auf eine Zeile. +Schreibe (die UNIX Pfade "a/b" und "" verbunden) auf eine Zeile. +Schreibe (die UNIX Pfade "" und "" verbunden) auf eine Zeile. +Schreibe (die UNIX Pfade "a/b" und "../../../xyz" verbunden) auf eine Zeile. + +[WINDOWS TESTS] + +[ Windows_Ist_Absolut Tests ] +Schreibe ("C:\\Users\\admin\\" ein absoluter Windows Pfad ist) auf eine Zeile. +Schreibe ("\\Users\\admin\\" ein absoluter Windows Pfad ist) auf eine Zeile. +Schreibe (":\\Users\\admin\\" ein absoluter Windows Pfad ist) auf eine Zeile. +Schreibe (" :" ein absoluter Windows Pfad ist) auf eine Zeile. +Schreibe ("" ein absoluter Windows Pfad ist) auf eine Zeile. + +[ Windows_Saeubern Tests ] +Schreibe (der Windows Pfad "C:\\Users\\admin" gesäubert) auf eine Zeile. +Schreibe (der Windows Pfad "C:\\Users\\你好" gesäubert) auf eine Zeile. +Schreibe (der Windows Pfad "C:\\Users\\admin\\" gesäubert) auf eine Zeile. +Schreibe (der Windows Pfad "C:\\Users\\admin\\.." gesäubert) auf eine Zeile. +Schreibe (der Windows Pfad "C:\\Users\\admin\\..\\" gesäubert) auf eine Zeile. +Schreibe (der Windows Pfad "C:\\Users\\admin\\." gesäubert) auf eine Zeile. +Schreibe (der Windows Pfad "C:\\Users\\admin\\.\\" gesäubert) auf eine Zeile. +Schreibe (der Windows Pfad "C:\\Users\\..\\admin\\." gesäubert) auf eine Zeile. +Schreibe (der Windows Pfad "C:\\Users\\\\admin" gesäubert) auf eine Zeile. +Schreibe (der Windows Pfad "C:\\.." gesäubert) auf eine Zeile. +Schreibe (der Windows Pfad "C:" gesäubert) auf eine Zeile. +Schreibe (der Windows Pfad ".." gesäubert) auf eine Zeile. [wollen wir dort \ ?] +Schreibe (der Windows Pfad "." gesäubert) auf eine Zeile. [wollen wir dort \ ?] +Schreibe (der Windows Pfad "" gesäubert) auf eine Zeile. + +[ Windows_Pfad_Verbinden Tests ] +Schreibe (die Windows Pfade "C:\\" und "admin" verbunden) auf eine Zeile. +Schreibe (die Windows Pfade "C:\\" und "admin\\" verbunden) auf eine Zeile. +Schreibe (die Windows Pfade "C:\\" und "admin\\.." verbunden) auf eine Zeile. +Schreibe (die Windows Pfade "C:\\" und "admin\\." verbunden) auf eine Zeile. +Schreibe (die Windows Pfade "C:\\.." und "admin" verbunden) auf eine Zeile. +Schreibe (die Windows Pfade "C:\\admin\\.." und "admin\\" verbunden) auf eine Zeile. +Schreibe (die Windows Pfade "\\a\\b" und "..\\..\\..\\xyz" verbunden) auf eine Zeile. + +[ Windows_Laufwerkbuchstabe Tests ] +Schreibe (den Laufwerkbuchstaben von "A:\\asf\\gjnu") auf eine Zeile. +Schreibe (den Laufwerkbuchstaben von "F:\\asf\\gjnu") auf eine Zeile. +Schreibe (den Laufwerkbuchstaben von "X:\\asf\\gjnu") auf eine Zeile. +Schreibe (den Laufwerkbuchstaben von "C:") auf eine Zeile. +Schreibe (den Laufwerkbuchstaben von "C") auf eine Zeile. +Schreibe (den Laufwerkbuchstaben von ":") auf eine Zeile. +Schreibe (den Laufwerkbuchstaben von " :") auf eine Zeile. +Schreibe (den Laufwerkbuchstaben von "") auf eine Zeile. + +[ Windows_Ordnerpfad Tests ] +Schreibe (den Windows Ordnerpfad von "C:\\Users\\admin\\test.c") auf eine Zeile. +Schreibe (den Windows Ordnerpfad von "\\Users\\admin\\test.c") auf eine Zeile. +Schreibe (den Windows Ordnerpfad von "C:\\test.c") auf eine Zeile. +Schreibe (den Windows Ordnerpfad von "\\test.c") auf eine Zeile. +Schreibe (den Windows Ordnerpfad von "") auf eine Zeile. + +[ Windows_Basisname Tests ] +Schreibe (den Windows Basisnamen von "C:\\a\\b.png") auf eine Zeile. +Schreibe (den Windows Basisnamen von "\\a\\b.png") auf eine Zeile. +Schreibe (den Windows Basisnamen von "C:\\a\b\\c") auf eine Zeile. +Schreibe (den Windows Basisnamen von "\\a\b\\c") auf eine Zeile. +Schreibe (den Windows Basisnamen von "C:/a/b/c//\\/") auf eine Zeile. +Schreibe (den Windows Basisnamen von "C:waa") auf eine Zeile. +Schreibe (den Windows Basisnamen von ".\\b") auf eine Zeile. +Schreibe (den Windows Basisnamen von "hi.txt") auf eine Zeile. +Schreibe (den Windows Basisnamen von "..") auf eine Zeile. +Schreibe (den Windows Basisnamen von ".") auf eine Zeile. +Schreibe (den Windows Basisnamen von "") auf eine Zeile. + +[ Windows_DateiName Tests ] +Schreibe (den Windows Dateinamen von "C:\\a\\b\\c\\test.txt") auf eine Zeile. +Schreibe (den Windows Dateinamen von "C:\\a\\b\\c\\test.txt.exe") auf eine Zeile. +Schreibe (den Windows Dateinamen von "C:/a/b/c/test.txt.exe") auf eine Zeile. +Schreibe (den Windows Dateinamen von "test.exe") auf eine Zeile. +Schreibe (den Windows Dateinamen von "\\a\\b\\c\\") auf eine Zeile. +Schreibe (den Windows Dateinamen von "\\a\\b\\c") auf eine Zeile. +Schreibe (den Windows Dateinamen von "\\") auf eine Zeile. +Schreibe (den Windows Dateinamen von "D:a.bat") auf eine Zeile. +Schreibe (den Windows Dateinamen von ".") auf eine Zeile. +Schreibe (den Windows Dateinamen von "..") auf eine Zeile. +Schreibe (den Windows Dateinamen von "noext") auf eine Zeile. +Schreibe (den Windows Dateinamen von "") auf eine Zeile. + +[ Windows_Erweiterung Tests ] +Schreibe (die Windows Erweiterung der Datei bei "C:\\a\\b\\c\\bar.css") auf eine Zeile. +Schreibe (die Windows Erweiterung der Datei bei "C:\\a\\b\\c\\foo.tar.gz") auf eine Zeile. +Schreibe (die Windows Erweiterung der Datei bei "/a/b/c/foo.tar.gz") auf eine Zeile. +Schreibe (die Windows Erweiterung der Datei bei "bar.css") auf eine Zeile. +Schreibe (die Windows Erweiterung der Datei bei "C:a.bat") auf eine Zeile. +Schreibe (die Windows Erweiterung der Datei bei "C:\\a\\b.trap\\c\\noext") auf eine Zeile. +Schreibe (die Windows Erweiterung der Datei bei "C:\\") auf eine Zeile. +Schreibe (die Windows Erweiterung der Datei bei "\\") auf eine Zeile. +Schreibe (die Windows Erweiterung der Datei bei ".") auf eine Zeile. +Schreibe (die Windows Erweiterung der Datei bei "..") auf eine Zeile. +Schreibe (die Windows Erweiterung der Datei bei "noext") auf eine Zeile. +Schreibe (die Windows Erweiterung der Datei bei "") auf eine Zeile. \ No newline at end of file diff --git a/tests/testdata/stdlib/Pfade/expected.txt b/tests/testdata/stdlib/Pfade/expected.txt index ed262fc4..cc68ff80 100644 --- a/tests/testdata/stdlib/Pfade/expected.txt +++ b/tests/testdata/stdlib/Pfade/expected.txt @@ -53,3 +53,77 @@ a/b a/b ../xyz +wahr +wahr +falsch +falsch +falsch +C:\Users\admin +C:\Users\你好 +C:\Users\admin\ +C:\Users +C:\Users\ +C:\Users\admin +C:\Users\admin\ +C:\admin +C:\Users\\admin +C:\ +C:\ +\ +\ +\ +C:\admin +C:\admin\ +C:\ +C:\admin +C:\admin +C:\admin\ +\xyz +A +F +X +C + + + + +C:\Users\admin +\Users\admin +C:\ +\ +. +b.png +b.png +c +c +c +waa +b +hi.txt +.. +. +. +test +test +test +test + + + +a + + + + +css +tar.gz +tar.gz +css +bat + + + + + + +