diff options
| author | Amlal <amlal@nekernel.org> | 2025-04-25 13:08:33 +0200 |
|---|---|---|
| committer | Amlal <amlal@nekernel.org> | 2025-04-25 13:08:33 +0200 |
| commit | fb790b07aeba8e22e4190cf3e1834d11ecde6c96 (patch) | |
| tree | 4cec7d1b321307b1d5935577631dae116a658a37 /public | |
| parent | 63a2d92c5dfe976175cda024ec01905d11b43738 (diff) | |
dev: better .clang-format, ran format command.
Signed-off-by: Amlal <amlal@nekernel.org>
Diffstat (limited to 'public')
24 files changed, 2083 insertions, 2453 deletions
diff --git a/public/frameworks/CoreFoundation.fwrk/headers/Array.h b/public/frameworks/CoreFoundation.fwrk/headers/Array.h index e9a36ac4..0b4a8dbf 100644 --- a/public/frameworks/CoreFoundation.fwrk/headers/Array.h +++ b/public/frameworks/CoreFoundation.fwrk/headers/Array.h @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. ------------------------------------------- */ @@ -8,64 +8,45 @@ #include <user/SystemCalls.h> -namespace CF -{ - template <typename T, SizeT N> - class CFArray final - { - public: - explicit CFArray() = default; - ~CFArray() = default; - - CFArray& operator=(const CFArray&) = default; - CFArray(const CFArray&) = default; - - T& operator[](SizeT at) - { - MUST_PASS(at < this->Count()); - return fArray[at]; - } - - Bool Empty() - { - return this->Count() > 0; - } - - SizeT Capacity() - { - return N; - } - - SizeT Count() - { - auto cnt = 0UL; - - for (auto i = 0UL; i < N; ++i) - { - if (fArray[i]) - ++cnt; - } - - return cnt; - } - - const T* CData() - { - return fArray; - } - - operator bool() - { - return !Empty(); - } - - private: - T fArray[N] = {nullptr}; - }; - - template <typename ValueType> - auto make_array(ValueType val) - { - return CFArray<ValueType, ARRAY_SIZE(val)>{val}; - } -} // namespace CF +namespace CF { +template <typename T, SizeT N> +class CFArray final { + public: + explicit CFArray() = default; + ~CFArray() = default; + + CFArray& operator=(const CFArray&) = default; + CFArray(const CFArray&) = default; + + T& operator[](SizeT at) { + MUST_PASS(at < this->Count()); + return fArray[at]; + } + + Bool Empty() { return this->Count() > 0; } + + SizeT Capacity() { return N; } + + SizeT Count() { + auto cnt = 0UL; + + for (auto i = 0UL; i < N; ++i) { + if (fArray[i]) ++cnt; + } + + return cnt; + } + + const T* CData() { return fArray; } + + operator bool() { return !Empty(); } + + private: + T fArray[N] = {nullptr}; +}; + +template <typename ValueType> +auto make_array(ValueType val) { + return CFArray<ValueType, ARRAY_SIZE(val)>{val}; +} +} // namespace CF diff --git a/public/frameworks/CoreFoundation.fwrk/headers/Atom.h b/public/frameworks/CoreFoundation.fwrk/headers/Atom.h index 923d6bce..f279f0b1 100644 --- a/public/frameworks/CoreFoundation.fwrk/headers/Atom.h +++ b/public/frameworks/CoreFoundation.fwrk/headers/Atom.h @@ -1,47 +1,33 @@ /* ------------------------------------------- - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. ------------------------------------------- */ #pragma once #include <CoreFoundation.fwrk/headers/Foundation.h> -namespace CF -{ - template <typename T> - class CFAtom final - { - public: - explicit CFAtom() = default; - ~CFAtom() = default; - - public: - CFAtom& operator=(const CFAtom&) = delete; - CFAtom(const CFAtom&) = delete; - - public: - T operator[](SizeT bit) - { - return (fArrayOfAtoms & (1 << bit)); - } - - void operator|(SizeT bit) - { - fArrayOfAtoms |= (1 << bit); - } - - friend Boolean operator==(CFAtom<T>& atomic, const T& idx) - { - return atomic[idx] == idx; - } - - friend Boolean operator!=(CFAtom<T>& atomic, const T& idx) - { - return atomic[idx] == idx; - } - - private: - T fArrayOfAtoms; - }; -} // namespace CF +namespace CF { +template <typename T> +class CFAtom final { + public: + explicit CFAtom() = default; + ~CFAtom() = default; + + public: + CFAtom& operator=(const CFAtom&) = delete; + CFAtom(const CFAtom&) = delete; + + public: + T operator[](SizeT bit) { return (fArrayOfAtoms & (1 << bit)); } + + void operator|(SizeT bit) { fArrayOfAtoms |= (1 << bit); } + + friend Boolean operator==(CFAtom<T>& atomic, const T& idx) { return atomic[idx] == idx; } + + friend Boolean operator!=(CFAtom<T>& atomic, const T& idx) { return atomic[idx] == idx; } + + private: + T fArrayOfAtoms; +}; +} // namespace CF diff --git a/public/frameworks/CoreFoundation.fwrk/headers/Foundation.h b/public/frameworks/CoreFoundation.fwrk/headers/Foundation.h index b1c37635..194b7bb7 100644 --- a/public/frameworks/CoreFoundation.fwrk/headers/Foundation.h +++ b/public/frameworks/CoreFoundation.fwrk/headers/Foundation.h @@ -1,10 +1,10 @@ /* ------------------------------------------- - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. - FILE: Foundation.h - PURPOSE: Foundation header of the CF framework. + FILE: Foundation.h + PURPOSE: Foundation header of the CF framework. ------------------------------------------- */ @@ -12,68 +12,64 @@ #include <user/SystemCalls.h> -namespace CF -{ - class CFString; - class CFGUID; - class CFProperty; - class CFObject; +namespace CF { +class CFString; +class CFGUID; +class CFProperty; +class CFObject; - template <typename T> - class CFRef; - class CFFont; - struct CFPoint; - struct CFRect; - struct CFColor; +template <typename T> +class CFRef; +class CFFont; +struct CFPoint; +struct CFRect; +struct CFColor; #ifndef __LP64__ - typedef SInt32 CFInteger; - typedef float CFReal; +typedef SInt32 CFInteger; +typedef float CFReal; #else - typedef SInt64 CFInteger; - typedef double CFReal; +typedef SInt64 CFInteger; +typedef double CFReal; #endif - typedef SInt32 CFInteger32; - typedef SInt64 CFInteger64; +typedef SInt32 CFInteger32; +typedef SInt64 CFInteger64; - typedef Char CFChar8; - typedef char16_t CFChar16; +typedef Char CFChar8; +typedef char16_t CFChar16; - struct CFPoint - { - CFInteger64 x_1{0UL}; - CFInteger64 y_1{0UL}; +struct CFPoint { + CFInteger64 x_1{0UL}; + CFInteger64 y_1{0UL}; - CFInteger64 x_2{0UL}; - CFInteger64 y_2{0UL}; - CFReal ang{0UL}; + CFInteger64 x_2{0UL}; + CFInteger64 y_2{0UL}; + CFReal ang{0UL}; - operator bool(); + operator bool(); - /// @brief Check if point is within the current CFPoint. - /// @param point the current point to check. - /// @retval true if point is within this point. - /// @retval validations failed. - bool IsWithin(CFPoint& point); - }; + /// @brief Check if point is within the current CFPoint. + /// @param point the current point to check. + /// @retval true if point is within this point. + /// @retval validations failed. + bool IsWithin(CFPoint& point); +}; - struct CFColor final - { - CFInteger64 r, g, b, a{0}; - }; +struct CFColor final { + CFInteger64 r, g, b, a{0}; +}; - struct CFRect final - { - CFInteger64 x{0UL}; - CFInteger64 y{0UL}; +struct CFRect final { + CFInteger64 x{0UL}; + CFInteger64 y{0UL}; - CFInteger64 width{0UL}; - CFInteger64 height{0UL}; + CFInteger64 width{0UL}; + CFInteger64 height{0UL}; - operator bool(); + operator bool(); - BOOL SizeMatches(CFRect& rect) noexcept; - BOOL PositionMatches(CFRect& rect) noexcept; - }; -} // namespace CF
\ No newline at end of file + BOOL SizeMatches(CFRect& rect) noexcept; + BOOL PositionMatches(CFRect& rect) noexcept; +}; +} // namespace CF
\ No newline at end of file diff --git a/public/frameworks/CoreFoundation.fwrk/headers/Object.h b/public/frameworks/CoreFoundation.fwrk/headers/Object.h index 733512b1..1692f20e 100644 --- a/public/frameworks/CoreFoundation.fwrk/headers/Object.h +++ b/public/frameworks/CoreFoundation.fwrk/headers/Object.h @@ -1,7 +1,7 @@ /* ------------------------------------------- - Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. + Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. ------------------------------------------- */ @@ -11,16 +11,14 @@ #define CF_OBJECT : public CF::CFObject -namespace CF -{ - class CFObject; +namespace CF { +class CFObject; - class CFObject - { - public: - explicit CFObject() = default; - virtual ~CFObject() = default; +class CFObject { + public: + explicit CFObject() = default; + virtual ~CFObject() = default; - SCI_COPY_DEFAULT(CFObject); - }; -} // namespace CF
\ No newline at end of file + SCI_COPY_DEFAULT(CFObject); +}; +} // namespace CF
\ No newline at end of file diff --git a/public/frameworks/CoreFoundation.fwrk/headers/Property.h b/public/frameworks/CoreFoundation.fwrk/headers/Property.h index b999c54e..58e881e5 100644 --- a/public/frameworks/CoreFoundation.fwrk/headers/Property.h +++ b/public/frameworks/CoreFoundation.fwrk/headers/Property.h @@ -1,53 +1,51 @@ /* ------------------------------------------- - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. ------------------------------------------- */ #ifndef _PROPS_H #define _PROPS_H -#include <user/SystemCalls.h> #include <CoreFoundation.fwrk/headers/Ref.h> +#include <user/SystemCalls.h> #define kMaxPropLen (256U) -namespace CF -{ - class CFString; - class CFProperty; - class CFGUID; - - template <typename Cls, SizeT N> - class CFArray; - - /// @brief handle to anything (number, ptr, string...) - using CFPropertyId = UIntPtr; - - /// @brief User property class. - /// @example /prop/foo or /prop/bar - class CFProperty final CF_OBJECT - { - public: - CFProperty(); - virtual ~CFProperty(); - - public: - CFProperty& operator=(const CFProperty&) = default; - CFProperty(const CFProperty&) = default; - - Bool StringEquals(CFString& name); - CFPropertyId& GetValue(); - CFString& GetKey(); - - private: - CFString* fName{nullptr}; - CFPropertyId fValue{0UL}; - Ref<CFGUID> fGUID{}; - }; - - template <SizeT N> - using CFPropertyArray = CFArray<CFProperty, N>; -} // namespace CF - -#endif // !CFKIT_PROPS_H +namespace CF { +class CFString; +class CFProperty; +class CFGUID; + +template <typename Cls, SizeT N> +class CFArray; + +/// @brief handle to anything (number, ptr, string...) +using CFPropertyId = UIntPtr; + +/// @brief User property class. +/// @example /prop/foo or /prop/bar +class CFProperty final CF_OBJECT { + public: + CFProperty(); + virtual ~CFProperty(); + + public: + CFProperty& operator=(const CFProperty&) = default; + CFProperty(const CFProperty&) = default; + + Bool StringEquals(CFString& name); + CFPropertyId& GetValue(); + CFString& GetKey(); + + private: + CFString* fName{nullptr}; + CFPropertyId fValue{0UL}; + Ref<CFGUID> fGUID{}; +}; + +template <SizeT N> +using CFPropertyArray = CFArray<CFProperty, N>; +} // namespace CF + +#endif // !CFKIT_PROPS_H diff --git a/public/frameworks/CoreFoundation.fwrk/headers/Ref.h b/public/frameworks/CoreFoundation.fwrk/headers/Ref.h index 2a4ec452..c18c6161 100644 --- a/public/frameworks/CoreFoundation.fwrk/headers/Ref.h +++ b/public/frameworks/CoreFoundation.fwrk/headers/Ref.h @@ -1,110 +1,81 @@ /* ------------------------------------------- - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. ------------------------------------------- */ #ifndef _REF_H_ #define _REF_H_ -#include <user/SystemCalls.h> #include <CoreFoundation.fwrk/headers/Object.h> +#include <user/SystemCalls.h> + +namespace CF { +template <typename T> +class CFRef; + +template <typename T> +class CFRef final CF_OBJECT { + public: + CFRef() = default; + + ~CFRef() { + if (MmGetHeapFlags(fClass) != -1) delete fClass; + } + + public: + CFRef(T* cls) : fClass(cls) {} + + CFRef(T cls) : fClass(&cls) {} + + CFRef& operator=(T ref) { + if (!fClass) return *this; + + fClass = &ref; + return *this; + } + + public: + T operator->() const { + MUST_PASS(*fClass); + return *fClass; + } + + T& Leak() noexcept { return *fClass; } + + T& TryLeak() const noexcept { + MUST_PASS(*fClass); + return *fClass; + } + + T operator*() { return *fClass; } + + operator bool() noexcept { return fClass; } + + private: + T* fClass{nullptr}; +}; + +template <typename T> +class CFNonNullRef final { + public: + CFNonNullRef() = delete; + CFNonNullRef(nullPtr) = delete; + + CFNonNullRef(T* ref) : fRef(ref) { MUST_PASS(ref); } + + CFRef<T>& operator->() { + MUST_PASS(fRef); + return fRef; + } + + CFNonNullRef& operator=(const CFNonNullRef<T>& ref) = delete; + CFNonNullRef(const CFNonNullRef<T>& ref) = default; + + private: + CFRef<T> fRef{nullptr}; +}; +} // namespace CF -namespace CF -{ - template <typename T> - class CFRef; - - template <typename T> - class CFRef final CF_OBJECT - { - public: - CFRef() = default; - - ~CFRef() - { - if (MmGetHeapFlags(fClass) != -1) - delete fClass; - } - - public: - CFRef(T* cls) - : fClass(cls) - { - } - - CFRef(T cls) - : fClass(&cls) - { - } - - CFRef& operator=(T ref) - { - if (!fClass) - return *this; - - fClass = &ref; - return *this; - } - - public: - T operator->() const - { - MUST_PASS(*fClass); - return *fClass; - } - - T& Leak() noexcept - { - return *fClass; - } - - T& TryLeak() const noexcept - { - MUST_PASS(*fClass); - return *fClass; - } - - T operator*() - { - return *fClass; - } - - operator bool() noexcept - { - return fClass; - } - - private: - T* fClass{nullptr}; - }; - - template <typename T> - class CFNonNullRef final - { - public: - CFNonNullRef() = delete; - CFNonNullRef(nullPtr) = delete; - - CFNonNullRef(T* ref) - : fRef(ref) - { - MUST_PASS(ref); - } - - CFRef<T>& operator->() - { - MUST_PASS(fRef); - return fRef; - } - - CFNonNullRef& operator=(const CFNonNullRef<T>& ref) = delete; - CFNonNullRef(const CFNonNullRef<T>& ref) = default; - - private: - CFRef<T> fRef{nullptr}; - }; -} // namespace CF - -#endif // ifndef _NEWKIT_REF_H_ +#endif // ifndef _NEWKIT_REF_H_ diff --git a/public/frameworks/CoreFoundation.fwrk/headers/String.h b/public/frameworks/CoreFoundation.fwrk/headers/String.h index e420ac91..c28c05cd 100644 --- a/public/frameworks/CoreFoundation.fwrk/headers/String.h +++ b/public/frameworks/CoreFoundation.fwrk/headers/String.h @@ -1,7 +1,7 @@ /* ------------------------------------------- - Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. + Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. ------------------------------------------- */ @@ -9,12 +9,10 @@ #include <CoreFoundation.fwrk/headers/Object.h> -namespace CF -{ - class CFString; +namespace CF { +class CFString; - class CFString final CF_OBJECT - { - public: - }; -} // namespace CF
\ No newline at end of file +class CFString final CF_OBJECT { + public: +}; +} // namespace CF
\ No newline at end of file diff --git a/public/frameworks/CoreFoundation.fwrk/src/Foundation.cc b/public/frameworks/CoreFoundation.fwrk/src/Foundation.cc index 89adf665..a4b84abf 100644 --- a/public/frameworks/CoreFoundation.fwrk/src/Foundation.cc +++ b/public/frameworks/CoreFoundation.fwrk/src/Foundation.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024 Amlal El Mahrouss, all rights reserved + Copyright (C) 2024 Amlal El Mahrouss, all rights reserved ------------------------------------------- */ @@ -9,25 +9,22 @@ /***********************************************************************************/ /// @brief returns true if the proportions are valid. /***********************************************************************************/ -CF::CFRect::operator bool() -{ - return width > 0 && height > 0; +CF::CFRect::operator bool() { + return width > 0 && height > 0; } /***********************************************************************************/ /// @brief returns true if size matches. /***********************************************************************************/ -BOOL CF::CFRect::SizeMatches(CF::CFRect& rect) noexcept -{ - return rect.height == height && rect.width == width; +BOOL CF::CFRect::SizeMatches(CF::CFRect& rect) noexcept { + return rect.height == height && rect.width == width; } /***********************************************************************************/ /// @brief returns true if position matches. /***********************************************************************************/ -BOOL CF::CFRect::PositionMatches(CF::CFRect& rect) noexcept -{ - return rect.y == y && rect.x == x; +BOOL CF::CFRect::PositionMatches(CF::CFRect& rect) noexcept { + return rect.y == y && rect.x == x; } /***********************************************************************************/ @@ -36,16 +33,14 @@ BOOL CF::CFRect::PositionMatches(CF::CFRect& rect) noexcept /// @retval true if point is within this point. /// @retval the validations have failed, false otherwise true. /***********************************************************************************/ -BOOL CF::CFPoint::IsWithin(CF::CFPoint& withinOf) -{ - return x_1 >= withinOf.x_1 && x_2 <= (withinOf.x_2) && - y_1 >= withinOf.y_1 && y_2 <= (withinOf.y_2); +BOOL CF::CFPoint::IsWithin(CF::CFPoint& withinOf) { + return x_1 >= withinOf.x_1 && x_2 <= (withinOf.x_2) && y_1 >= withinOf.y_1 && + y_2 <= (withinOf.y_2); } /***********************************************************************************/ /// @brief if Point object is correctly set up. /***********************************************************************************/ -CF::CFPoint::operator bool() -{ - return x_1 > x_2 && y_1 > y_2; +CF::CFPoint::operator bool() { + return x_1 > x_2 && y_1 > y_2; }
\ No newline at end of file diff --git a/public/frameworks/DiskImage.fwrk/headers/DiskImage.h b/public/frameworks/DiskImage.fwrk/headers/DiskImage.h index c0566485..78b39bf8 100644 --- a/public/frameworks/DiskImage.fwrk/headers/DiskImage.h +++ b/public/frameworks/DiskImage.fwrk/headers/DiskImage.h @@ -1,51 +1,49 @@ /* ------------------------------------------- - Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. + Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. + + FILE: DiskImage.h + PURPOSE: Disk Imaging framework. - FILE: DiskImage.h - PURPOSE: Disk Imaging framework. - ------------------------------------------- */ #pragma once #include <user/SystemCalls.h> -#define kDISectorSz (512) -#define kDIMinDiskSz mib_cast(1) +#define kDISectorSz (512) +#define kDIMinDiskSz mib_cast(1) #define kDIDefaultOutputName "disk.eimg" -#define kDIDefaultDiskName "Disk" -#define kDISuccessStatus (0) -#define kDIFailureStatus (1) +#define kDIDefaultDiskName "Disk" +#define kDISuccessStatus (0) +#define kDIFailureStatus (1) #define kDIDiskNameLen (16) -#define kDIOutNameLen (256) - -namespace DI -{ - /// @brief Disk Image file structure. - /// @param disk_name Disk partition name. - /// @param sector_sz Disk sector_sz. - /// @param block_cnt Disk block count. - /// @param disk_sz Disk size. - /// @param out_name Output file name. - struct DI_DISK_IMAGE - { - Char disk_name[kDIDiskNameLen] = kDIDefaultDiskName; - SInt32 sector_sz = kDISectorSz; - SInt32 block_cnt = 0; - SizeT disk_sz = kDIMinDiskSz; - Char out_name[kDIOutNameLen] = kDIDefaultOutputName; - }; - - /// @brief Format with an EPM partition. - /// @param img disk image structure. - /// @return Status code upon completion. - SInt32 DIFormatPartitionEPM(struct DI_DISK_IMAGE& img) noexcept; - - /// @brief NeFS format over EPM. - /// @param img disk image structure. - /// @return Status code upon completion. - SInt32 DIFormatFilesystemNeFS(struct DI_DISK_IMAGE& img) noexcept; - -} // namespace DI +#define kDIOutNameLen (256) + +namespace DI { +/// @brief Disk Image file structure. +/// @param disk_name Disk partition name. +/// @param sector_sz Disk sector_sz. +/// @param block_cnt Disk block count. +/// @param disk_sz Disk size. +/// @param out_name Output file name. +struct DI_DISK_IMAGE { + Char disk_name[kDIDiskNameLen] = kDIDefaultDiskName; + SInt32 sector_sz = kDISectorSz; + SInt32 block_cnt = 0; + SizeT disk_sz = kDIMinDiskSz; + Char out_name[kDIOutNameLen] = kDIDefaultOutputName; +}; + +/// @brief Format with an EPM partition. +/// @param img disk image structure. +/// @return Status code upon completion. +SInt32 DIFormatPartitionEPM(struct DI_DISK_IMAGE& img) noexcept; + +/// @brief NeFS format over EPM. +/// @param img disk image structure. +/// @return Status code upon completion. +SInt32 DIFormatFilesystemNeFS(struct DI_DISK_IMAGE& img) noexcept; + +} // namespace DI diff --git a/public/frameworks/DiskImage.fwrk/src/DiskImage+EPM.cc b/public/frameworks/DiskImage.fwrk/src/DiskImage+EPM.cc index 4d2a6694..a1182e64 100644 --- a/public/frameworks/DiskImage.fwrk/src/DiskImage+EPM.cc +++ b/public/frameworks/DiskImage.fwrk/src/DiskImage+EPM.cc @@ -1,53 +1,46 @@ /* ------------------------------------------- - Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. + Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. - FILE: DiskImage+EPM.cc - PURPOSE: Disk Imaging framework. + FILE: DiskImage+EPM.cc + PURPOSE: Disk Imaging framework. ------------------------------------------- */ #include <DiskImage.fwrk/headers/DiskImage.h> -#include <FirmwareKit/EPM.h> #include <FSKit/NeFS.h> +#include <FirmwareKit/EPM.h> /// @brief EPM format disk /// @param img disk image structure. /// @return Status code upon completion. -SInt32 DI::DIFormatPartitionEPM(struct DI_DISK_IMAGE& img) noexcept -{ - if (!img.sector_sz || (img.sector_sz % 512 != 0)) - return kDIFailureStatus; +SInt32 DI::DIFormatPartitionEPM(struct DI_DISK_IMAGE& img) noexcept { + if (!img.sector_sz || (img.sector_sz % 512 != 0)) return kDIFailureStatus; - if (*img.out_name == 0 || - *img.disk_name == 0) - return kDIFailureStatus; + if (*img.out_name == 0 || *img.disk_name == 0) return kDIFailureStatus; - struct ::EPM_PART_BLOCK block - { - }; + struct ::EPM_PART_BLOCK block {}; - block.NumBlocks = img.block_cnt; - block.SectorSz = img.sector_sz; - block.Version = kEPMRevisionBcd; - block.LbaStart = sizeof(struct ::EPM_PART_BLOCK); - block.LbaEnd = img.disk_sz - block.LbaStart; - block.FsVersion = kNeFSVersionInteger; + block.NumBlocks = img.block_cnt; + block.SectorSz = img.sector_sz; + block.Version = kEPMRevisionBcd; + block.LbaStart = sizeof(struct ::EPM_PART_BLOCK); + block.LbaEnd = img.disk_sz - block.LbaStart; + block.FsVersion = kNeFSVersionInteger; - ::MmCopyMemory(block.Name, (VoidPtr)img.disk_name, ::MmStrLen(img.disk_name)); - ::MmCopyMemory(block.Magic, (VoidPtr)kEPMMagic86, ::MmStrLen(kEPMMagic86)); + ::MmCopyMemory(block.Name, (VoidPtr) img.disk_name, ::MmStrLen(img.disk_name)); + ::MmCopyMemory(block.Magic, (VoidPtr) kEPMMagic86, ::MmStrLen(kEPMMagic86)); - IORef handle = IoOpenFile(img.out_name, nullptr); + IORef handle = IoOpenFile(img.out_name, nullptr); - if (!handle) - return kDIFailureStatus; + if (!handle) return kDIFailureStatus; - ::IoWriteFile(handle, (Char*)&block, sizeof(struct ::EPM_PART_BLOCK)); + ::IoWriteFile(handle, (Char*) &block, sizeof(struct ::EPM_PART_BLOCK)); - ::IoCloseFile(handle); + ::IoCloseFile(handle); - handle = nullptr; + handle = nullptr; - return kDISuccessStatus; + return kDISuccessStatus; } diff --git a/public/frameworks/DiskImage.fwrk/src/DiskImage+NeFS.cc b/public/frameworks/DiskImage.fwrk/src/DiskImage+NeFS.cc index 4928c878..bee84cca 100644 --- a/public/frameworks/DiskImage.fwrk/src/DiskImage+NeFS.cc +++ b/public/frameworks/DiskImage.fwrk/src/DiskImage+NeFS.cc @@ -1,64 +1,57 @@ /* ------------------------------------------- - Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. + Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. - FILE: DiskImage+NeFS.cc - PURPOSE: Disk Imaging framework. + FILE: DiskImage+NeFS.cc + PURPOSE: Disk Imaging framework. ------------------------------------------- */ #include <DiskImage.fwrk/headers/DiskImage.h> -#include <FirmwareKit/EPM.h> #include <FSKit/NeFS.h> +#include <FirmwareKit/EPM.h> /// @brief NeFS format over EPM. /// @param img disk image structure. /// @return Status code upon completion. -SInt32 DI::DIFormatFilesystemNeFS(struct DI_DISK_IMAGE& img) noexcept -{ - if (!img.sector_sz || (img.sector_sz % 512 != 0)) - return kDIFailureStatus; +SInt32 DI::DIFormatFilesystemNeFS(struct DI_DISK_IMAGE& img) noexcept { + if (!img.sector_sz || (img.sector_sz % 512 != 0)) return kDIFailureStatus; - if (*img.out_name == 0 || - *img.disk_name == 0) - return kDIFailureStatus; + if (*img.out_name == 0 || *img.disk_name == 0) return kDIFailureStatus; - struct ::NEFS_ROOT_PARTITION_BLOCK rpb - { - }; + struct ::NEFS_ROOT_PARTITION_BLOCK rpb {}; - ::MmCopyMemory(rpb.PartitionName, (VoidPtr)img.disk_name, ::MmStrLen(img.disk_name)); - ::MmCopyMemory(rpb.Ident, (VoidPtr)kNeFSIdent, ::MmStrLen(kNeFSIdent)); + ::MmCopyMemory(rpb.PartitionName, (VoidPtr) img.disk_name, ::MmStrLen(img.disk_name)); + ::MmCopyMemory(rpb.Ident, (VoidPtr) kNeFSIdent, ::MmStrLen(kNeFSIdent)); - rpb.Version = kNeFSVersionInteger; - rpb.EpmBlock = kEPMBootBlockLba; + rpb.Version = kNeFSVersionInteger; + rpb.EpmBlock = kEPMBootBlockLba; - rpb.StartCatalog = kNeFSCatalogStartAddress; - rpb.CatalogCount = 0; + rpb.StartCatalog = kNeFSCatalogStartAddress; + rpb.CatalogCount = 0; - rpb.DiskSize = img.disk_sz; + rpb.DiskSize = img.disk_sz; - rpb.SectorSize = img.sector_sz; - rpb.SectorCount = rpb.DiskSize / rpb.SectorSize; + rpb.SectorSize = img.sector_sz; + rpb.SectorCount = rpb.DiskSize / rpb.SectorSize; - rpb.FreeSectors = rpb.SectorCount; - rpb.FreeCatalog = rpb.DiskSize / sizeof(NEFS_CATALOG_STRUCT); + rpb.FreeSectors = rpb.SectorCount; + rpb.FreeCatalog = rpb.DiskSize / sizeof(NEFS_CATALOG_STRUCT); - IORef handle = IoOpenFile(img.out_name, nullptr); + IORef handle = IoOpenFile(img.out_name, nullptr); - if (!handle) - return kDIFailureStatus; + if (!handle) return kDIFailureStatus; - UInt64 p_prev = ::IoTellFile(handle); + UInt64 p_prev = ::IoTellFile(handle); - ::IoWriteFile(handle, (Char*)&rpb, sizeof(struct ::NEFS_ROOT_PARTITION_BLOCK)); + ::IoWriteFile(handle, (Char*) &rpb, sizeof(struct ::NEFS_ROOT_PARTITION_BLOCK)); - ::IoSeekFile(handle, p_prev); + ::IoSeekFile(handle, p_prev); - ::IoCloseFile(handle); + ::IoCloseFile(handle); - handle = nullptr; + handle = nullptr; - return kDISuccessStatus; + return kDISuccessStatus; }
\ No newline at end of file diff --git a/public/frameworks/KernelTest.fwrk/headers/KernelTest.h b/public/frameworks/KernelTest.fwrk/headers/KernelTest.h index e3200032..808d127e 100644 --- a/public/frameworks/KernelTest.fwrk/headers/KernelTest.h +++ b/public/frameworks/KernelTest.fwrk/headers/KernelTest.h @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. + Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. ------------------------------------------- */ @@ -12,27 +12,24 @@ /// @file KernelTest.h #define KT_TEST_VERSION_BCD (0x0001) -#define KT_TEST_VERSION "0.0.1" +#define KT_TEST_VERSION "0.0.1" #define KT_TEST_FAILURE (1) #define KT_TEST_SUCCESS (0) #define KT_DECL_TEST(NAME, FN) \ - class KT_##NAME final \ - { \ - public: \ - void Run(); \ - const char* ToString(); \ - }; \ - inline void KT_##NAME::Run() \ - { \ - MUST_PASS(FN() == true); \ - } \ - inline const char* KT_##NAME::ToString() \ - { \ - return #FN; \ - } + class KT_##NAME final { \ + public: \ + void Run(); \ + const char* ToString(); \ + }; \ + inline void KT_##NAME::Run() { \ + MUST_PASS(FN() == true); \ + } \ + inline const char* KT_##NAME::ToString() { \ + return #FN; \ + } KT_DECL_TEST(ALWAYS_BREAK, []() -> bool { return false; }); KT_DECL_TEST(ALWAYS_GOOD, []() -> bool { return true; });
\ No newline at end of file diff --git a/public/tools/cc/src/CommandLine.cc b/public/tools/cc/src/CommandLine.cc index d9420c47..719a1555 100644 --- a/public/tools/cc/src/CommandLine.cc +++ b/public/tools/cc/src/CommandLine.cc @@ -8,8 +8,8 @@ /// @brief Placeholder program. -SInt32 main(SInt32 argc, Char* argv[]) -{ - PrintOut(nullptr, "cc: A C++ compiler to be installed.\rcc: This program is present as a placeholder."); - return EXIT_FAILURE; +SInt32 main(SInt32 argc, Char* argv[]) { + PrintOut(nullptr, + "cc: A C++ compiler to be installed.\rcc: This program is present as a placeholder."); + return EXIT_FAILURE; } diff --git a/public/tools/diutil/src/CommandLine.cc b/public/tools/diutil/src/CommandLine.cc index ef0aaa2e..dd23f532 100644 --- a/public/tools/diutil/src/CommandLine.cc +++ b/public/tools/diutil/src/CommandLine.cc @@ -1,67 +1,58 @@ /* ------------------------------------------- - Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. + Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. - FILE: CommandLine.cc - PURPOSE: DIUTIL CLI. + FILE: CommandLine.cc + PURPOSE: DIUTIL CLI. ------------------------------------------- */ #include <DiskImage.fwrk/headers/DiskImage.h> static const Char kDiskName[kDIDiskNameLen] = "Empty Disk"; -static SInt32 kDiskSectorSz = kDISectorSz; -static SizeT kDiskSz = gib_cast(4); -static const Char kOutDisk[kDIOutNameLen] = "disk.eimg"; +static SInt32 kDiskSectorSz = kDISectorSz; +static SizeT kDiskSz = gib_cast(4); +static const Char kOutDisk[kDIOutNameLen] = "disk.eimg"; /// @brief Disk Utility entrypoint. -SInt32 _NeMain(SInt32 argc, Char** argv) -{ - for (SInt32 arg = 0; arg < argc; ++arg) - { - const Char* arg_s = argv[arg]; - - if (MmCmpMemory((VoidPtr)arg_s, (VoidPtr) "-diutil-output-name", MmStrLen("-diutil-output-name") == 0)) - { - if ((arg + 1) < argc) - { - MmCopyMemory((VoidPtr)kOutDisk, argv[arg + 1], kDIDiskNameLen); - } - } - else if (MmCmpMemory((VoidPtr)arg_s, (VoidPtr) "-diutil-output-size", MmStrLen("-diutil-output-size") == 0)) - { - if ((arg + 1) < argc) - { - kDiskSz = StrMathToNumber(argv[arg + 1], nullptr, 10); - } - } - else if (MmCmpMemory((VoidPtr)arg_s, (VoidPtr) "-diutil-sector-size", MmStrLen("-diutil-sector-size") == 0)) - { - if ((arg + 1) < argc) - { - kDiskSectorSz = StrMathToNumber(argv[arg + 1], nullptr, 10); - } - } - else if (MmCmpMemory((VoidPtr)arg_s, (VoidPtr) "-diutil-part-name", MmStrLen("-diutil-part-name") == 0)) - { - if ((arg + 1) < argc) - { - MmCopyMemory((VoidPtr)kDiskName, argv[arg + 1], kDIDiskNameLen); - } - } - } - - // create disk image, by appending an EPM partition to it. - - DI::DI_DISK_IMAGE img{}; - - img.disk_sz = kDiskSz; - img.sector_sz = kDiskSectorSz; - img.block_cnt = 0; - - MmCopyMemory((VoidPtr)img.disk_name, (VoidPtr)kDiskName, kDIDiskNameLen); - MmCopyMemory((VoidPtr)img.out_name, (VoidPtr)kOutDisk, kDIDiskNameLen); - - // format disk image to explicit partition map. - return DI::DIFormatPartitionEPM(img); +SInt32 _NeMain(SInt32 argc, Char** argv) { + for (SInt32 arg = 0; arg < argc; ++arg) { + const Char* arg_s = argv[arg]; + + if (MmCmpMemory((VoidPtr) arg_s, (VoidPtr) "-diutil-output-name", + MmStrLen("-diutil-output-name") == 0)) { + if ((arg + 1) < argc) { + MmCopyMemory((VoidPtr) kOutDisk, argv[arg + 1], kDIDiskNameLen); + } + } else if (MmCmpMemory((VoidPtr) arg_s, (VoidPtr) "-diutil-output-size", + MmStrLen("-diutil-output-size") == 0)) { + if ((arg + 1) < argc) { + kDiskSz = StrMathToNumber(argv[arg + 1], nullptr, 10); + } + } else if (MmCmpMemory((VoidPtr) arg_s, (VoidPtr) "-diutil-sector-size", + MmStrLen("-diutil-sector-size") == 0)) { + if ((arg + 1) < argc) { + kDiskSectorSz = StrMathToNumber(argv[arg + 1], nullptr, 10); + } + } else if (MmCmpMemory((VoidPtr) arg_s, (VoidPtr) "-diutil-part-name", + MmStrLen("-diutil-part-name") == 0)) { + if ((arg + 1) < argc) { + MmCopyMemory((VoidPtr) kDiskName, argv[arg + 1], kDIDiskNameLen); + } + } + } + + // create disk image, by appending an EPM partition to it. + + DI::DI_DISK_IMAGE img{}; + + img.disk_sz = kDiskSz; + img.sector_sz = kDiskSectorSz; + img.block_cnt = 0; + + MmCopyMemory((VoidPtr) img.disk_name, (VoidPtr) kDiskName, kDIDiskNameLen); + MmCopyMemory((VoidPtr) img.out_name, (VoidPtr) kOutDisk, kDIDiskNameLen); + + // format disk image to explicit partition map. + return DI::DIFormatPartitionEPM(img); }
\ No newline at end of file diff --git a/public/tools/diutil/vendor/Dialogs.h b/public/tools/diutil/vendor/Dialogs.h index fd64026b..ce50b811 100644 --- a/public/tools/diutil/vendor/Dialogs.h +++ b/public/tools/diutil/vendor/Dialogs.h @@ -16,45 +16,45 @@ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN 1 #endif -#include <windows.h> #include <commdlg.h> -#include <shlobj.h> -#include <shobjidl.h> // IFileDialog #include <shellapi.h> +#include <shlobj.h> +#include <shobjidl.h> // IFileDialog #include <strsafe.h> -#include <future> // std::async -#include <userenv.h> // GetUserProfileDirectory() +#include <userenv.h> // GetUserProfileDirectory() +#include <windows.h> +#include <future> // std::async #elif __EMSCRIPTEN__ #include <emscripten.h> #else #ifndef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 2 // for popen() +#define _POSIX_C_SOURCE 2 // for popen() #endif #ifdef __APPLE__ #ifndef _DARWIN_C_SOURCE #define _DARWIN_C_SOURCE #endif #endif -#include <cstdio> // popen() -#include <cstdlib> // std::getenv() -#include <fcntl.h> // fcntl() -#include <unistd.h> // read(), pipe(), dup2(), getuid() -#include <csignal> // ::kill, std::signal -#include <sys/stat.h> // stat() -#include <sys/wait.h> // waitpid() -#include <pwd.h> // getpwnam() +#include <fcntl.h> // fcntl() +#include <pwd.h> // getpwnam() +#include <sys/stat.h> // stat() +#include <sys/wait.h> // waitpid() +#include <unistd.h> // read(), pipe(), dup2(), getuid() +#include <csignal> // ::kill, std::signal +#include <cstdio> // popen() +#include <cstdlib> // std::getenv() #endif -#include <string> // std::string -#include <memory> // std::shared_ptr -#include <iostream> // std::ostream -#include <map> // std::map -#include <set> // std::set -#include <regex> // std::regex -#include <thread> // std::mutex, std::this_thread -#include <chrono> // std::chrono +#include <chrono> // std::chrono +#include <iostream> // std::ostream +#include <map> // std::map +#include <memory> // std::shared_ptr +#include <regex> // std::regex +#include <set> // std::set +#include <string> // std::string +#include <thread> // std::mutex, std::this_thread // Versions of mingw64 g++ up to 9.3.0 do not have a complete IFileDialog #ifndef PFD_HAS_IFILEDIALOG @@ -67,1915 +67,1672 @@ #endif #endif -namespace pfd -{ - - enum class button - { - cancel = -1, - ok, - yes, - no, - abort, - retry, - ignore, - }; - - enum class choice - { - ok = 0, - ok_cancel, - yes_no, - yes_no_cancel, - retry_cancel, - abort_retry_ignore, - }; - - enum class icon - { - info = 0, - warning, - error, - question, - }; - - // Additional option flags for various dialog constructors - enum class opt : uint8_t - { - none = 0, - // For file open, allow multiselect. - multiselect = 0x1, - // For file save, force overwrite and disable the confirmation dialog. - force_overwrite = 0x2, - // For folder select, force path to be the provided argument instead - // of the last opened directory, which is the Microsoft-recommended, - // user-friendly behaviour. - force_path = 0x4, - }; - - inline opt operator|(opt a, opt b) - { - return opt(uint8_t(a) | uint8_t(b)); - } - inline bool operator&(opt a, opt b) - { - return bool(uint8_t(a) & uint8_t(b)); - } - - // The settings class, only exposing to the user a way to set verbose mode - // and to force a rescan of installed desktop helpers (zenity, kdialog…). - class settings - { - public: - static bool available(); - - static void verbose(bool value); - static void rescan(); - - protected: - explicit settings(bool resync = false); - - bool check_program(std::string const& program); - - inline bool is_osascript() const; - inline bool is_zenity() const; - inline bool is_kdialog() const; - - enum class flag - { - is_scanned = 0, - is_verbose, - - has_zenity, - has_matedialog, - has_qarma, - has_kdialog, - is_vista, - - max_flag, - }; - - // Static array of flags for internal state - bool const& flags(flag in_flag) const; - - // Non-const getter for the static array of flags - bool& flags(flag in_flag); - }; - - // Internal classes, not to be used by client applications - namespace internal - { - - // Process wait timeout, in milliseconds - static int const default_wait_timeout = 20; - - class executor - { - friend class dialog; - - public: - // High level function to get the result of a command - std::string result(int* exit_code = nullptr); - - // High level function to abort - bool kill(); +namespace pfd { + +enum class button { + cancel = -1, + ok, + yes, + no, + abort, + retry, + ignore, +}; + +enum class choice { + ok = 0, + ok_cancel, + yes_no, + yes_no_cancel, + retry_cancel, + abort_retry_ignore, +}; + +enum class icon { + info = 0, + warning, + error, + question, +}; + +// Additional option flags for various dialog constructors +enum class opt : uint8_t { + none = 0, + // For file open, allow multiselect. + multiselect = 0x1, + // For file save, force overwrite and disable the confirmation dialog. + force_overwrite = 0x2, + // For folder select, force path to be the provided argument instead + // of the last opened directory, which is the Microsoft-recommended, + // user-friendly behaviour. + force_path = 0x4, +}; + +inline opt operator|(opt a, opt b) { + return opt(uint8_t(a) | uint8_t(b)); +} +inline bool operator&(opt a, opt b) { + return bool(uint8_t(a) & uint8_t(b)); +} + +// The settings class, only exposing to the user a way to set verbose mode +// and to force a rescan of installed desktop helpers (zenity, kdialog…). +class settings { + public: + static bool available(); + + static void verbose(bool value); + static void rescan(); + + protected: + explicit settings(bool resync = false); + + bool check_program(std::string const& program); + + inline bool is_osascript() const; + inline bool is_zenity() const; + inline bool is_kdialog() const; + + enum class flag { + is_scanned = 0, + is_verbose, + + has_zenity, + has_matedialog, + has_qarma, + has_kdialog, + is_vista, + + max_flag, + }; + + // Static array of flags for internal state + bool const& flags(flag in_flag) const; + + // Non-const getter for the static array of flags + bool& flags(flag in_flag); +}; + +// Internal classes, not to be used by client applications +namespace internal { + + // Process wait timeout, in milliseconds + static int const default_wait_timeout = 20; + + class executor { + friend class dialog; + + public: + // High level function to get the result of a command + std::string result(int* exit_code = nullptr); + + // High level function to abort + bool kill(); #if _WIN32 - void start_func(std::function<std::string(int*)> const& fun); - static BOOL CALLBACK enum_windows_callback(HWND hwnd, LPARAM lParam); + void start_func(std::function<std::string(int*)> const& fun); + static BOOL CALLBACK enum_windows_callback(HWND hwnd, LPARAM lParam); #elif __EMSCRIPTEN__ - void start(int exit_code); + void start(int exit_code); #else - void start_process(std::vector<std::string> const& command); + void start_process(std::vector<std::string> const& command); #endif - ~executor(); + ~executor(); - protected: - bool ready(int timeout = default_wait_timeout); - void stop(); + protected: + bool ready(int timeout = default_wait_timeout); + void stop(); - private: - bool m_running = false; - std::string m_stdout; - int m_exit_code = -1; + private: + bool m_running = false; + std::string m_stdout; + int m_exit_code = -1; #if _WIN32 - std::future<std::string> m_future; - std::set<HWND> m_windows; - std::condition_variable m_cond; - std::mutex m_mutex; - DWORD m_tid; + std::future<std::string> m_future; + std::set<HWND> m_windows; + std::condition_variable m_cond; + std::mutex m_mutex; + DWORD m_tid; #elif __EMSCRIPTEN__ || __NX__ - // FIXME: do something + // FIXME: do something #else - pid_t m_pid = 0; - int m_fd = -1; + pid_t m_pid = 0; + int m_fd = -1; #endif - }; + }; - class platform - { - protected: + class platform { + protected: #if _WIN32 - // Helper class around LoadLibraryA() and GetProcAddress() with some safety - class dll - { - public: - dll(std::string const& name); - ~dll(); - - template <typename T> - class proc - { - public: - proc(dll const& lib, std::string const& sym) - : m_proc(reinterpret_cast<T*>((void*)::GetProcAddress(lib.handle, sym.c_str()))) - { - } - - operator bool() const - { - return m_proc != nullptr; - } - operator T*() const - { - return m_proc; - } - - private: - T* m_proc; - }; - - private: - HMODULE handle; - }; - - // Helper class around CoInitialize() and CoUnInitialize() - class ole32_dll : public dll - { - public: - ole32_dll(); - ~ole32_dll(); - bool is_initialized(); - - private: - HRESULT m_state; - }; - - // Helper class around CreateActCtx() and ActivateActCtx() - class new_style_context - { - public: - new_style_context(); - ~new_style_context(); - - private: - HANDLE create(); - ULONG_PTR m_cookie = 0; - }; + // Helper class around LoadLibraryA() and GetProcAddress() with some safety + class dll { + public: + dll(std::string const& name); + ~dll(); + + template <typename T> + class proc { + public: + proc(dll const& lib, std::string const& sym) + : m_proc(reinterpret_cast<T*>((void*) ::GetProcAddress(lib.handle, sym.c_str()))) {} + + operator bool() const { return m_proc != nullptr; } + operator T*() const { return m_proc; } + + private: + T* m_proc; + }; + + private: + HMODULE handle; + }; + + // Helper class around CoInitialize() and CoUnInitialize() + class ole32_dll : public dll { + public: + ole32_dll(); + ~ole32_dll(); + bool is_initialized(); + + private: + HRESULT m_state; + }; + + // Helper class around CreateActCtx() and ActivateActCtx() + class new_style_context { + public: + new_style_context(); + ~new_style_context(); + + private: + HANDLE create(); + ULONG_PTR m_cookie = 0; + }; #endif - }; - - class dialog : protected settings, protected platform - { - public: - bool ready(int timeout = default_wait_timeout) const; - bool kill() const; - - protected: - explicit dialog(); - - std::vector<std::string> desktop_helper() const; - static std::string buttons_to_name(choice _choice); - static std::string get_icon_name(icon _icon); - - std::string powershell_quote(std::string const& str) const; - std::string osascript_quote(std::string const& str) const; - std::string shell_quote(std::string const& str) const; - - // Keep handle to executing command - std::shared_ptr<executor> m_async; - }; - - class file_dialog : public dialog - { - protected: - enum type - { - open, - save, - folder, - }; - - file_dialog(type in_type, - std::string const& title, - std::string const& default_path = "", - std::vector<std::string> const& filters = {}, - opt options = opt::none); - - protected: - std::string string_result(); - std::vector<std::string> vector_result(); + }; + + class dialog : protected settings, protected platform { + public: + bool ready(int timeout = default_wait_timeout) const; + bool kill() const; + + protected: + explicit dialog(); + + std::vector<std::string> desktop_helper() const; + static std::string buttons_to_name(choice _choice); + static std::string get_icon_name(icon _icon); + + std::string powershell_quote(std::string const& str) const; + std::string osascript_quote(std::string const& str) const; + std::string shell_quote(std::string const& str) const; + + // Keep handle to executing command + std::shared_ptr<executor> m_async; + }; + + class file_dialog : public dialog { + protected: + enum type { + open, + save, + folder, + }; + + file_dialog(type in_type, std::string const& title, std::string const& default_path = "", + std::vector<std::string> const& filters = {}, opt options = opt::none); + + protected: + std::string string_result(); + std::vector<std::string> vector_result(); #if _WIN32 - static int CALLBACK bffcallback(HWND hwnd, UINT uMsg, LPARAM, LPARAM pData); + static int CALLBACK bffcallback(HWND hwnd, UINT uMsg, LPARAM, LPARAM pData); #if PFD_HAS_IFILEDIALOG - std::string select_folder_vista(IFileDialog* ifd, bool force_path); + std::string select_folder_vista(IFileDialog* ifd, bool force_path); #endif - std::wstring m_wtitle; - std::wstring m_wdefault_path; + std::wstring m_wtitle; + std::wstring m_wdefault_path; - std::vector<std::string> m_vector_result; + std::vector<std::string> m_vector_result; #endif - }; - - } // namespace internal - - // - // The path class provides some platform-specific path constants - // - - class path : protected internal::platform - { - public: - static std::string home(); - static std::string separator(); - }; - - // - // The notify widget - // - - class notify : public internal::dialog - { - public: - notify(std::string const& title, - std::string const& message, - icon _icon = icon::info); - }; - - // - // The message widget - // - - class message : public internal::dialog - { - public: - message(std::string const& title, - std::string const& text, - choice _choice = choice::ok_cancel, - icon _icon = icon::info); - - button result(); - - private: - // Some extra logic to map the exit code to button number - std::map<int, button> m_mappings; - }; - - // - // The open_file, save_file, and open_folder widgets - // - - class open_file : public internal::file_dialog - { - public: - open_file(std::string const& title, - std::string const& default_path = "", - std::vector<std::string> const& filters = {"All Files", "*"}, - opt options = opt::none); + }; + +} // namespace internal + +// +// The path class provides some platform-specific path constants +// + +class path : protected internal::platform { + public: + static std::string home(); + static std::string separator(); +}; + +// +// The notify widget +// + +class notify : public internal::dialog { + public: + notify(std::string const& title, std::string const& message, icon _icon = icon::info); +}; + +// +// The message widget +// + +class message : public internal::dialog { + public: + message(std::string const& title, std::string const& text, choice _choice = choice::ok_cancel, + icon _icon = icon::info); + + button result(); + + private: + // Some extra logic to map the exit code to button number + std::map<int, button> m_mappings; +}; + +// +// The open_file, save_file, and open_folder widgets +// + +class open_file : public internal::file_dialog { + public: + open_file(std::string const& title, std::string const& default_path = "", + std::vector<std::string> const& filters = {"All Files", "*"}, opt options = opt::none); #if defined(__has_cpp_attribute) #if __has_cpp_attribute(deprecated) - // Backwards compatibility - [[deprecated("Use pfd::opt::multiselect instead of allow_multiselect")]] + // Backwards compatibility + [[deprecated("Use pfd::opt::multiselect instead of allow_multiselect")]] #endif #endif - open_file(std::string const& title, - std::string const& default_path, - std::vector<std::string> const& filters, - bool allow_multiselect); - - std::vector<std::string> result(); - }; - - class save_file : public internal::file_dialog - { - public: - save_file(std::string const& title, - std::string const& default_path = "", - std::vector<std::string> const& filters = {"All Files", "*"}, - opt options = opt::none); + open_file(std::string const& title, std::string const& default_path, + std::vector<std::string> const& filters, bool allow_multiselect); + + std::vector<std::string> result(); +}; + +class save_file : public internal::file_dialog { + public: + save_file(std::string const& title, std::string const& default_path = "", + std::vector<std::string> const& filters = {"All Files", "*"}, opt options = opt::none); #if defined(__has_cpp_attribute) #if __has_cpp_attribute(deprecated) - // Backwards compatibility - [[deprecated("Use pfd::opt::force_overwrite instead of confirm_overwrite")]] + // Backwards compatibility + [[deprecated("Use pfd::opt::force_overwrite instead of confirm_overwrite")]] #endif #endif - save_file(std::string const& title, - std::string const& default_path, - std::vector<std::string> const& filters, - bool confirm_overwrite); - - std::string result(); - }; - - class select_folder : public internal::file_dialog - { - public: - select_folder(std::string const& title, - std::string const& default_path = "", - opt options = opt::none); - - std::string result(); - }; - - // - // Below this are all the method implementations. You may choose to define the - // macro PFD_SKIP_IMPLEMENTATION everywhere before including this header except - // in one place. This may reduce compilation times. - // + save_file(std::string const& title, std::string const& default_path, + std::vector<std::string> const& filters, bool confirm_overwrite); + + std::string result(); +}; + +class select_folder : public internal::file_dialog { + public: + select_folder(std::string const& title, std::string const& default_path = "", + opt options = opt::none); + + std::string result(); +}; + +// +// Below this are all the method implementations. You may choose to define the +// macro PFD_SKIP_IMPLEMENTATION everywhere before including this header except +// in one place. This may reduce compilation times. +// #if !defined PFD_SKIP_IMPLEMENTATION - // internal free functions implementations +// internal free functions implementations - namespace internal - { +namespace internal { #if _WIN32 - static inline std::wstring str2wstr(std::string const& str) - { - int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.size(), nullptr, 0); - std::wstring ret(len, '\0'); - MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.size(), (LPWSTR)ret.data(), (int)ret.size()); - return ret; - } - - static inline std::string wstr2str(std::wstring const& str) - { - int len = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), (int)str.size(), nullptr, 0, nullptr, nullptr); - std::string ret(len, '\0'); - WideCharToMultiByte(CP_UTF8, 0, str.c_str(), (int)str.size(), (LPSTR)ret.data(), (int)ret.size(), nullptr, nullptr); - return ret; - } - - static inline bool is_vista() - { - OSVERSIONINFOEXW osvi; - memset(&osvi, 0, sizeof(osvi)); - DWORDLONG const mask = VerSetConditionMask( - VerSetConditionMask( - VerSetConditionMask( - 0, VER_MAJORVERSION, VER_GREATER_EQUAL), - VER_MINORVERSION, VER_GREATER_EQUAL), - VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); - osvi.dwOSVersionInfoSize = sizeof(osvi); - osvi.dwMajorVersion = HIBYTE(_WIN32_WINNT_VISTA); - osvi.dwMinorVersion = LOBYTE(_WIN32_WINNT_VISTA); - osvi.wServicePackMajor = 0; - - return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, mask) != FALSE; - } + static inline std::wstring str2wstr(std::string const& str) { + int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int) str.size(), nullptr, 0); + std::wstring ret(len, '\0'); + MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int) str.size(), (LPWSTR) ret.data(), + (int) ret.size()); + return ret; + } + + static inline std::string wstr2str(std::wstring const& str) { + int len = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), (int) str.size(), nullptr, 0, nullptr, + nullptr); + std::string ret(len, '\0'); + WideCharToMultiByte(CP_UTF8, 0, str.c_str(), (int) str.size(), (LPSTR) ret.data(), + (int) ret.size(), nullptr, nullptr); + return ret; + } + + static inline bool is_vista() { + OSVERSIONINFOEXW osvi; + memset(&osvi, 0, sizeof(osvi)); + DWORDLONG const mask = VerSetConditionMask( + VerSetConditionMask(VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL), + VER_MINORVERSION, VER_GREATER_EQUAL), + VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + osvi.dwOSVersionInfoSize = sizeof(osvi); + osvi.dwMajorVersion = HIBYTE(_WIN32_WINNT_VISTA); + osvi.dwMinorVersion = LOBYTE(_WIN32_WINNT_VISTA); + osvi.wServicePackMajor = 0; + + return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, + mask) != FALSE; + } #endif - // This is necessary until C++20 which will have std::string::ends_with() etc. + // This is necessary until C++20 which will have std::string::ends_with() etc. - static inline bool ends_with(std::string const& str, std::string const& suffix) - { - return suffix.size() <= str.size() && - str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; - } + static inline bool ends_with(std::string const& str, std::string const& suffix) { + return suffix.size() <= str.size() && + str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; + } - static inline bool starts_with(std::string const& str, std::string const& prefix) - { - return prefix.size() <= str.size() && - str.compare(0, prefix.size(), prefix) == 0; - } + static inline bool starts_with(std::string const& str, std::string const& prefix) { + return prefix.size() <= str.size() && str.compare(0, prefix.size(), prefix) == 0; + } - // This is necessary until C++17 which will have std::filesystem::is_directory + // This is necessary until C++17 which will have std::filesystem::is_directory - static inline bool is_directory(std::string const& path) - { + static inline bool is_directory(std::string const& path) { #if _WIN32 - auto attr = GetFileAttributesA(path.c_str()); - return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY); + auto attr = GetFileAttributesA(path.c_str()); + return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY); #elif __EMSCRIPTEN__ - // TODO - return false; + // TODO + return false; #else - struct stat s; - return stat(path.c_str(), &s) == 0 && S_ISDIR(s.st_mode); + struct stat s; + return stat(path.c_str(), &s) == 0 && S_ISDIR(s.st_mode); #endif - } + } - // This is necessary because getenv is not thread-safe + // This is necessary because getenv is not thread-safe - static inline std::string getenv(std::string const& str) - { + static inline std::string getenv(std::string const& str) { #if _MSC_VER - char* buf = nullptr; - size_t size = 0; - if (_dupenv_s(&buf, &size, str.c_str()) == 0 && buf) - { - std::string ret(buf); - free(buf); - return ret; - } - return ""; + char* buf = nullptr; + size_t size = 0; + if (_dupenv_s(&buf, &size, str.c_str()) == 0 && buf) { + std::string ret(buf); + free(buf); + return ret; + } + return ""; #else - auto buf = std::getenv(str.c_str()); - return buf ? buf : ""; + auto buf = std::getenv(str.c_str()); + return buf ? buf : ""; #endif - } + } - } // namespace internal +} // namespace internal - // settings implementation +// settings implementation - inline settings::settings(bool resync) - { - flags(flag::is_scanned) &= !resync; +inline settings::settings(bool resync) { + flags(flag::is_scanned) &= !resync; - if (flags(flag::is_scanned)) - return; + if (flags(flag::is_scanned)) return; - auto pfd_verbose = internal::getenv("PFD_VERBOSE"); - auto match_no = std::regex("(|0|no|false)", std::regex_constants::icase); - if (!std::regex_match(pfd_verbose, match_no)) - flags(flag::is_verbose) = true; + auto pfd_verbose = internal::getenv("PFD_VERBOSE"); + auto match_no = std::regex("(|0|no|false)", std::regex_constants::icase); + if (!std::regex_match(pfd_verbose, match_no)) flags(flag::is_verbose) = true; #if _WIN32 - flags(flag::is_vista) = internal::is_vista(); + flags(flag::is_vista) = internal::is_vista(); #elif !__APPLE__ - flags(flag::has_zenity) = check_program("zenity"); - flags(flag::has_matedialog) = check_program("matedialog"); - flags(flag::has_qarma) = check_program("qarma"); - flags(flag::has_kdialog) = check_program("kdialog"); - - // If multiple helpers are available, try to default to the best one - if (flags(flag::has_zenity) && flags(flag::has_kdialog)) - { - auto desktop_name = internal::getenv("XDG_SESSION_DESKTOP"); - if (desktop_name == std::string("gnome")) - flags(flag::has_kdialog) = false; - else if (desktop_name == std::string("KDE")) - flags(flag::has_zenity) = false; - } + flags(flag::has_zenity) = check_program("zenity"); + flags(flag::has_matedialog) = check_program("matedialog"); + flags(flag::has_qarma) = check_program("qarma"); + flags(flag::has_kdialog) = check_program("kdialog"); + + // If multiple helpers are available, try to default to the best one + if (flags(flag::has_zenity) && flags(flag::has_kdialog)) { + auto desktop_name = internal::getenv("XDG_SESSION_DESKTOP"); + if (desktop_name == std::string("gnome")) + flags(flag::has_kdialog) = false; + else if (desktop_name == std::string("KDE")) + flags(flag::has_zenity) = false; + } #endif - flags(flag::is_scanned) = true; - } + flags(flag::is_scanned) = true; +} - inline bool settings::available() - { +inline bool settings::available() { #if _WIN32 - return true; + return true; #elif __APPLE__ - return true; + return true; #elif __EMSCRIPTEN__ - // FIXME: Return true after implementation is complete. - return false; + // FIXME: Return true after implementation is complete. + return false; #else - settings tmp; - return tmp.flags(flag::has_zenity) || - tmp.flags(flag::has_matedialog) || - tmp.flags(flag::has_qarma) || - tmp.flags(flag::has_kdialog); + settings tmp; + return tmp.flags(flag::has_zenity) || tmp.flags(flag::has_matedialog) || + tmp.flags(flag::has_qarma) || tmp.flags(flag::has_kdialog); #endif - } +} - inline void settings::verbose(bool value) - { - settings().flags(flag::is_verbose) = value; - } +inline void settings::verbose(bool value) { + settings().flags(flag::is_verbose) = value; +} - inline void settings::rescan() - { - settings(/* resync = */ true); - } +inline void settings::rescan() { + settings(/* resync = */ true); +} - // Check whether a program is present using “which”. - inline bool settings::check_program(std::string const& program) - { +// Check whether a program is present using “which”. +inline bool settings::check_program(std::string const& program) { #if _WIN32 - (void)program; - return false; + (void) program; + return false; #elif __EMSCRIPTEN__ - (void)program; - return false; + (void) program; + return false; #else - int exit_code = -1; - internal::executor async; - async.start_process({"/bin/sh", "-c", "which " + program}); - async.result(&exit_code); - return exit_code == 0; + int exit_code = -1; + internal::executor async; + async.start_process({"/bin/sh", "-c", "which " + program}); + async.result(&exit_code); + return exit_code == 0; #endif - } +} - inline bool settings::is_osascript() const - { +inline bool settings::is_osascript() const { #if __APPLE__ - return true; + return true; #else - return false; + return false; #endif - } - - inline bool settings::is_zenity() const - { - return flags(flag::has_zenity) || - flags(flag::has_matedialog) || - flags(flag::has_qarma); - } - - inline bool settings::is_kdialog() const - { - return flags(flag::has_kdialog); - } - - inline bool const& settings::flags(flag in_flag) const - { - static bool flags[size_t(flag::max_flag)]; - return flags[size_t(in_flag)]; - } - - inline bool& settings::flags(flag in_flag) - { - return const_cast<bool&>(static_cast<settings const*>(this)->flags(in_flag)); - } - - // path implementation - inline std::string path::home() - { +} + +inline bool settings::is_zenity() const { + return flags(flag::has_zenity) || flags(flag::has_matedialog) || flags(flag::has_qarma); +} + +inline bool settings::is_kdialog() const { + return flags(flag::has_kdialog); +} + +inline bool const& settings::flags(flag in_flag) const { + static bool flags[size_t(flag::max_flag)]; + return flags[size_t(in_flag)]; +} + +inline bool& settings::flags(flag in_flag) { + return const_cast<bool&>(static_cast<settings const*>(this)->flags(in_flag)); +} + +// path implementation +inline std::string path::home() { #if _WIN32 - // First try the USERPROFILE environment variable - auto user_profile = internal::getenv("USERPROFILE"); - if (user_profile.size() > 0) - return user_profile; - // Otherwise, try GetUserProfileDirectory() - HANDLE token = nullptr; - DWORD len = MAX_PATH; - char buf[MAX_PATH] = {'\0'}; - if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) - { - dll userenv("userenv.dll"); - dll::proc<BOOL WINAPI(HANDLE, LPSTR, LPDWORD)> get_user_profile_directory(userenv, "GetUserProfileDirectoryA"); - get_user_profile_directory(token, buf, &len); - CloseHandle(token); - if (*buf) - return buf; - } + // First try the USERPROFILE environment variable + auto user_profile = internal::getenv("USERPROFILE"); + if (user_profile.size() > 0) return user_profile; + // Otherwise, try GetUserProfileDirectory() + HANDLE token = nullptr; + DWORD len = MAX_PATH; + char buf[MAX_PATH] = {'\0'}; + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) { + dll userenv("userenv.dll"); + dll::proc<BOOL WINAPI(HANDLE, LPSTR, LPDWORD)> get_user_profile_directory( + userenv, "GetUserProfileDirectoryA"); + get_user_profile_directory(token, buf, &len); + CloseHandle(token); + if (*buf) return buf; + } #elif __EMSCRIPTEN__ - return "/"; + return "/"; #else - // First try the HOME environment variable - auto home = internal::getenv("HOME"); - if (home.size() > 0) - return home; - // Otherwise, try getpwuid_r() - size_t len = 4096; + // First try the HOME environment variable + auto home = internal::getenv("HOME"); + if (home.size() > 0) return home; + // Otherwise, try getpwuid_r() + size_t len = 4096; #if defined(_SC_GETPW_R_SIZE_MAX) - auto size_max = sysconf(_SC_GETPW_R_SIZE_MAX); - if (size_max != -1) - len = size_t(size_max); + auto size_max = sysconf(_SC_GETPW_R_SIZE_MAX); + if (size_max != -1) len = size_t(size_max); #endif - std::vector<char> buf(len); - struct passwd pwd, *result; - if (getpwuid_r(getuid(), &pwd, buf.data(), buf.size(), &result) == 0) - return result->pw_dir; + std::vector<char> buf(len); + struct passwd pwd, *result; + if (getpwuid_r(getuid(), &pwd, buf.data(), buf.size(), &result) == 0) return result->pw_dir; #endif - return "/"; - } + return "/"; +} - inline std::string path::separator() - { +inline std::string path::separator() { #if _WIN32 - return "\\"; + return "\\"; #else - return "/"; + return "/"; #endif - } +} - // executor implementation +// executor implementation - inline std::string internal::executor::result(int* exit_code /* = nullptr */) - { - stop(); - if (exit_code) - *exit_code = m_exit_code; - return m_stdout; - } +inline std::string internal::executor::result(int* exit_code /* = nullptr */) { + stop(); + if (exit_code) *exit_code = m_exit_code; + return m_stdout; +} - inline bool internal::executor::kill() - { +inline bool internal::executor::kill() { #if _WIN32 - if (m_future.valid()) - { - // Close all windows that weren’t open when we started the future - auto previous_windows = m_windows; - EnumWindows(&enum_windows_callback, (LPARAM)this); - for (auto hwnd : m_windows) - if (previous_windows.find(hwnd) == previous_windows.end()) - { - SendMessage(hwnd, WM_CLOSE, 0, 0); - // Also send IDNO in case of a Yes/No or Abort/Retry/Ignore messagebox - SendMessage(hwnd, WM_COMMAND, IDNO, 0); - } - } + if (m_future.valid()) { + // Close all windows that weren’t open when we started the future + auto previous_windows = m_windows; + EnumWindows(&enum_windows_callback, (LPARAM) this); + for (auto hwnd : m_windows) + if (previous_windows.find(hwnd) == previous_windows.end()) { + SendMessage(hwnd, WM_CLOSE, 0, 0); + // Also send IDNO in case of a Yes/No or Abort/Retry/Ignore messagebox + SendMessage(hwnd, WM_COMMAND, IDNO, 0); + } + } #elif __EMSCRIPTEN__ || __NX__ - // FIXME: do something - return false; // cannot kill + // FIXME: do something + return false; // cannot kill #else - ::kill(m_pid, SIGKILL); + ::kill(m_pid, SIGKILL); #endif - stop(); - return true; - } + stop(); + return true; +} #if _WIN32 - inline BOOL CALLBACK internal::executor::enum_windows_callback(HWND hwnd, LPARAM lParam) - { - auto that = (executor*)lParam; - - DWORD pid; - auto tid = GetWindowThreadProcessId(hwnd, &pid); - if (tid == that->m_tid) - that->m_windows.insert(hwnd); - return TRUE; - } +inline BOOL CALLBACK internal::executor::enum_windows_callback(HWND hwnd, LPARAM lParam) { + auto that = (executor*) lParam; + + DWORD pid; + auto tid = GetWindowThreadProcessId(hwnd, &pid); + if (tid == that->m_tid) that->m_windows.insert(hwnd); + return TRUE; +} #endif #if _WIN32 - inline void internal::executor::start_func(std::function<std::string(int*)> const& fun) - { - stop(); - - auto trampoline = [fun, this]() { - // Save our thread id so that the caller can cancel us - m_tid = GetCurrentThreadId(); - EnumWindows(&enum_windows_callback, (LPARAM)this); - m_cond.notify_all(); - return fun(&m_exit_code); - }; - - std::unique_lock<std::mutex> lock(m_mutex); - m_future = std::async(std::launch::async, trampoline); - m_cond.wait(lock); - m_running = true; - } +inline void internal::executor::start_func(std::function<std::string(int*)> const& fun) { + stop(); + + auto trampoline = [fun, this]() { + // Save our thread id so that the caller can cancel us + m_tid = GetCurrentThreadId(); + EnumWindows(&enum_windows_callback, (LPARAM) this); + m_cond.notify_all(); + return fun(&m_exit_code); + }; + + std::unique_lock<std::mutex> lock(m_mutex); + m_future = std::async(std::launch::async, trampoline); + m_cond.wait(lock); + m_running = true; +} #elif __EMSCRIPTEN__ - inline void internal::executor::start(int exit_code) - { - m_exit_code = exit_code; - } +inline void internal::executor::start(int exit_code) { + m_exit_code = exit_code; +} #else - inline void internal::executor::start_process(std::vector<std::string> const& command) - { - stop(); - m_stdout.clear(); - m_exit_code = -1; - - int in[2], out[2]; - if (pipe(in) != 0 || pipe(out) != 0) - return; - - m_pid = fork(); - if (m_pid < 0) - return; - - close(in[m_pid ? 0 : 1]); - close(out[m_pid ? 1 : 0]); - - if (m_pid == 0) - { - dup2(in[0], STDIN_FILENO); - dup2(out[1], STDOUT_FILENO); - - // Ignore stderr so that it doesn’t pollute the console (e.g. GTK+ errors from zenity) - int fd = open("/dev/null", O_WRONLY); - dup2(fd, STDERR_FILENO); - close(fd); - - std::vector<char*> args; - std::transform(command.cbegin(), command.cend(), std::back_inserter(args), - [](std::string const& s) { return const_cast<char*>(s.c_str()); }); - args.push_back(nullptr); // null-terminate argv[] - - execvp(args[0], args.data()); - exit(1); - } - - close(in[1]); - m_fd = out[0]; - auto flags = fcntl(m_fd, F_GETFL); - fcntl(m_fd, F_SETFL, flags | O_NONBLOCK); - - m_running = true; - } +inline void internal::executor::start_process(std::vector<std::string> const& command) { + stop(); + m_stdout.clear(); + m_exit_code = -1; + + int in[2], out[2]; + if (pipe(in) != 0 || pipe(out) != 0) return; + + m_pid = fork(); + if (m_pid < 0) return; + + close(in[m_pid ? 0 : 1]); + close(out[m_pid ? 1 : 0]); + + if (m_pid == 0) { + dup2(in[0], STDIN_FILENO); + dup2(out[1], STDOUT_FILENO); + + // Ignore stderr so that it doesn’t pollute the console (e.g. GTK+ errors from zenity) + int fd = open("/dev/null", O_WRONLY); + dup2(fd, STDERR_FILENO); + close(fd); + + std::vector<char*> args; + std::transform(command.cbegin(), command.cend(), std::back_inserter(args), + [](std::string const& s) { return const_cast<char*>(s.c_str()); }); + args.push_back(nullptr); // null-terminate argv[] + + execvp(args[0], args.data()); + exit(1); + } + + close(in[1]); + m_fd = out[0]; + auto flags = fcntl(m_fd, F_GETFL); + fcntl(m_fd, F_SETFL, flags | O_NONBLOCK); + + m_running = true; +} #endif - inline internal::executor::~executor() - { - stop(); - } +inline internal::executor::~executor() { + stop(); +} - inline bool internal::executor::ready(int timeout /* = default_wait_timeout */) - { - if (!m_running) - return true; +inline bool internal::executor::ready(int timeout /* = default_wait_timeout */) { + if (!m_running) return true; #if _WIN32 - if (m_future.valid()) - { - auto status = m_future.wait_for(std::chrono::milliseconds(timeout)); - if (status != std::future_status::ready) - { - // On Windows, we need to run the message pump. If the async - // thread uses a Windows API dialog, it may be attached to the - // main thread and waiting for messages that only we can dispatch. - MSG msg; - while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - return false; - } - - m_stdout = m_future.get(); - } + if (m_future.valid()) { + auto status = m_future.wait_for(std::chrono::milliseconds(timeout)); + if (status != std::future_status::ready) { + // On Windows, we need to run the message pump. If the async + // thread uses a Windows API dialog, it may be attached to the + // main thread and waiting for messages that only we can dispatch. + MSG msg; + while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return false; + } + + m_stdout = m_future.get(); + } #elif __EMSCRIPTEN__ || __NX__ - // FIXME: do something - (void)timeout; + // FIXME: do something + (void) timeout; #else - char buf[BUFSIZ]; - ssize_t received = read(m_fd, buf, BUFSIZ); // Flawfinder: ignore - if (received > 0) - { - m_stdout += std::string(buf, received); - return false; - } - - // Reap child process if it is dead. It is possible that the system has already reaped it - // (this happens when the calling application handles or ignores SIG_CHLD) and results in - // waitpid() failing with ECHILD. Otherwise we assume the child is running and we sleep for - // a little while. - int status; - pid_t child = waitpid(m_pid, &status, WNOHANG); - if (child != m_pid && (child >= 0 || errno != ECHILD)) - { - // FIXME: this happens almost always at first iteration - std::this_thread::sleep_for(std::chrono::milliseconds(timeout)); - return false; - } - - close(m_fd); - m_exit_code = WEXITSTATUS(status); + char buf[BUFSIZ]; + ssize_t received = read(m_fd, buf, BUFSIZ); // Flawfinder: ignore + if (received > 0) { + m_stdout += std::string(buf, received); + return false; + } + + // Reap child process if it is dead. It is possible that the system has already reaped it + // (this happens when the calling application handles or ignores SIG_CHLD) and results in + // waitpid() failing with ECHILD. Otherwise we assume the child is running and we sleep for + // a little while. + int status; + pid_t child = waitpid(m_pid, &status, WNOHANG); + if (child != m_pid && (child >= 0 || errno != ECHILD)) { + // FIXME: this happens almost always at first iteration + std::this_thread::sleep_for(std::chrono::milliseconds(timeout)); + return false; + } + + close(m_fd); + m_exit_code = WEXITSTATUS(status); #endif - m_running = false; - return true; - } + m_running = false; + return true; +} - inline void internal::executor::stop() - { - // Loop until the user closes the dialog - while (!ready()) - ; - } +inline void internal::executor::stop() { + // Loop until the user closes the dialog + while (!ready()); +} - // dll implementation +// dll implementation #if _WIN32 - inline internal::platform::dll::dll(std::string const& name) - : handle(::LoadLibraryA(name.c_str())) - { - } +inline internal::platform::dll::dll(std::string const& name) + : handle(::LoadLibraryA(name.c_str())) {} - inline internal::platform::dll::~dll() - { - if (handle) - ::FreeLibrary(handle); - } -#endif // _WIN32 +inline internal::platform::dll::~dll() { + if (handle) ::FreeLibrary(handle); +} +#endif // _WIN32 - // ole32_dll implementation +// ole32_dll implementation #if _WIN32 - inline internal::platform::ole32_dll::ole32_dll() - : dll("ole32.dll") - { - // Use COINIT_MULTITHREADED because COINIT_APARTMENTTHREADED causes crashes. - // See https://github.com/samhocevar/portable-file-dialogs/issues/51 - auto coinit = proc<HRESULT WINAPI(LPVOID, DWORD)>(*this, "CoInitializeEx"); - m_state = coinit(nullptr, COINIT_MULTITHREADED); - } - - inline internal::platform::ole32_dll::~ole32_dll() - { - if (is_initialized()) - proc<void WINAPI()>(*this, "CoUninitialize")(); - } - - inline bool internal::platform::ole32_dll::is_initialized() - { - return m_state == S_OK || m_state == S_FALSE; - } +inline internal::platform::ole32_dll::ole32_dll() : dll("ole32.dll") { + // Use COINIT_MULTITHREADED because COINIT_APARTMENTTHREADED causes crashes. + // See https://github.com/samhocevar/portable-file-dialogs/issues/51 + auto coinit = proc<HRESULT WINAPI(LPVOID, DWORD)>(*this, "CoInitializeEx"); + m_state = coinit(nullptr, COINIT_MULTITHREADED); +} + +inline internal::platform::ole32_dll::~ole32_dll() { + if (is_initialized()) proc<void WINAPI()>(*this, "CoUninitialize")(); +} + +inline bool internal::platform::ole32_dll::is_initialized() { + return m_state == S_OK || m_state == S_FALSE; +} #endif - // new_style_context implementation +// new_style_context implementation #if _WIN32 - inline internal::platform::new_style_context::new_style_context() - { - // Only create one activation context for the whole app lifetime. - static HANDLE hctx = create(); - - if (hctx != INVALID_HANDLE_VALUE) - ActivateActCtx(hctx, &m_cookie); - } - - inline internal::platform::new_style_context::~new_style_context() - { - DeactivateActCtx(0, m_cookie); - } - - inline HANDLE internal::platform::new_style_context::create() - { - // This “hack” seems to be necessary for this code to work on windows XP. - // Without it, dialogs do not show and close immediately. GetError() - // returns 0 so I don’t know what causes this. I was not able to reproduce - // this behavior on Windows 7 and 10 but just in case, let it be here for - // those versions too. - // This hack is not required if other dialogs are used (they load comdlg32 - // automatically), only if message boxes are used. - dll comdlg32("comdlg32.dll"); - - // Using approach as shown here: https://stackoverflow.com/a/10444161 - UINT len = ::GetSystemDirectoryA(nullptr, 0); - std::string sys_dir(len, '\0'); - ::GetSystemDirectoryA(&sys_dir[0], len); - - ACTCTXA act_ctx = - { - // Do not set flag ACTCTX_FLAG_SET_PROCESS_DEFAULT, since it causes a - // crash with error “default context is already set”. - sizeof(act_ctx), - ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID, - "shell32.dll", - 0, - 0, - sys_dir.c_str(), - (LPCSTR)124, - nullptr, - 0, - }; - - return ::CreateActCtxA(&act_ctx); - } -#endif // _WIN32 - - // dialog implementation - - inline bool internal::dialog::ready(int timeout /* = default_wait_timeout */) const - { - return m_async->ready(timeout); - } - - inline bool internal::dialog::kill() const - { - return m_async->kill(); - } - - inline internal::dialog::dialog() - : m_async(std::make_shared<executor>()) - { - } - - inline std::vector<std::string> internal::dialog::desktop_helper() const - { +inline internal::platform::new_style_context::new_style_context() { + // Only create one activation context for the whole app lifetime. + static HANDLE hctx = create(); + + if (hctx != INVALID_HANDLE_VALUE) ActivateActCtx(hctx, &m_cookie); +} + +inline internal::platform::new_style_context::~new_style_context() { + DeactivateActCtx(0, m_cookie); +} + +inline HANDLE internal::platform::new_style_context::create() { + // This “hack” seems to be necessary for this code to work on windows XP. + // Without it, dialogs do not show and close immediately. GetError() + // returns 0 so I don’t know what causes this. I was not able to reproduce + // this behavior on Windows 7 and 10 but just in case, let it be here for + // those versions too. + // This hack is not required if other dialogs are used (they load comdlg32 + // automatically), only if message boxes are used. + dll comdlg32("comdlg32.dll"); + + // Using approach as shown here: https://stackoverflow.com/a/10444161 + UINT len = ::GetSystemDirectoryA(nullptr, 0); + std::string sys_dir(len, '\0'); + ::GetSystemDirectoryA(&sys_dir[0], len); + + ACTCTXA act_ctx = { + // Do not set flag ACTCTX_FLAG_SET_PROCESS_DEFAULT, since it causes a + // crash with error “default context is already set”. + sizeof(act_ctx), + ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID, + "shell32.dll", + 0, + 0, + sys_dir.c_str(), + (LPCSTR) 124, + nullptr, + 0, + }; + + return ::CreateActCtxA(&act_ctx); +} +#endif // _WIN32 + +// dialog implementation + +inline bool internal::dialog::ready(int timeout /* = default_wait_timeout */) const { + return m_async->ready(timeout); +} + +inline bool internal::dialog::kill() const { + return m_async->kill(); +} + +inline internal::dialog::dialog() : m_async(std::make_shared<executor>()) {} + +inline std::vector<std::string> internal::dialog::desktop_helper() const { #if __APPLE__ - return {"osascript"}; + return {"osascript"}; #else - return {flags(flag::has_zenity) ? "zenity" - : flags(flag::has_matedialog) ? "matedialog" - : flags(flag::has_qarma) ? "qarma" - : flags(flag::has_kdialog) ? "kdialog" - : "echo"}; + return {flags(flag::has_zenity) ? "zenity" + : flags(flag::has_matedialog) ? "matedialog" + : flags(flag::has_qarma) ? "qarma" + : flags(flag::has_kdialog) ? "kdialog" + : "echo"}; #endif - } - - inline std::string internal::dialog::buttons_to_name(choice _choice) - { - switch (_choice) - { - case choice::ok_cancel: - return "okcancel"; - case choice::yes_no: - return "yesno"; - case choice::yes_no_cancel: - return "yesnocancel"; - case choice::retry_cancel: - return "retrycancel"; - case choice::abort_retry_ignore: - return "abortretryignore"; - /* case choice::ok: */ default: - return "ok"; - } - } - - inline std::string internal::dialog::get_icon_name(icon _icon) - { - switch (_icon) - { - case icon::warning: - return "warning"; - case icon::error: - return "error"; - case icon::question: - return "question"; - // Zenity wants "information" but WinForms wants "info" - /* case icon::info: */ default: +} + +inline std::string internal::dialog::buttons_to_name(choice _choice) { + switch (_choice) { + case choice::ok_cancel: + return "okcancel"; + case choice::yes_no: + return "yesno"; + case choice::yes_no_cancel: + return "yesnocancel"; + case choice::retry_cancel: + return "retrycancel"; + case choice::abort_retry_ignore: + return "abortretryignore"; + /* case choice::ok: */ default: + return "ok"; + } +} + +inline std::string internal::dialog::get_icon_name(icon _icon) { + switch (_icon) { + case icon::warning: + return "warning"; + case icon::error: + return "error"; + case icon::question: + return "question"; + // Zenity wants "information" but WinForms wants "info" + /* case icon::info: */ default: #if _WIN32 - return "info"; + return "info"; #else - return "information"; + return "information"; #endif - } - } - - // This is only used for debugging purposes - inline std::ostream& operator<<(std::ostream& s, std::vector<std::string> const& v) - { - int not_first = 0; - for (auto& e : v) - s << (not_first++ ? " " : "") << e; - return s; - } - - // Properly quote a string for Powershell: replace ' or " with '' or "" - // FIXME: we should probably get rid of newlines! - // FIXME: the \" sequence seems unsafe, too! - // XXX: this is no longer used but I would like to keep it around just in case - inline std::string internal::dialog::powershell_quote(std::string const& str) const - { - return "'" + std::regex_replace(str, std::regex("['\"]"), "$&$&") + "'"; - } - - // Properly quote a string for osascript: replace \ or " with \\ or \" - // XXX: this also used to replace ' with \' when popen was used, but it would be - // smarter to do shell_quote(osascript_quote(...)) if this is needed again. - inline std::string internal::dialog::osascript_quote(std::string const& str) const - { - return "\"" + std::regex_replace(str, std::regex("[\\\\\"]"), "\\$&") + "\""; - } - - // Properly quote a string for the shell: just replace ' with '\'' - // XXX: this is no longer used but I would like to keep it around just in case - inline std::string internal::dialog::shell_quote(std::string const& str) const - { - return "'" + std::regex_replace(str, std::regex("'"), "'\\''") + "'"; - } - - // file_dialog implementation - - inline internal::file_dialog::file_dialog(type in_type, - std::string const& title, - std::string const& default_path /* = "" */, - std::vector<std::string> const& filters /* = {} */, - opt options /* = opt::none */) - { + } +} + +// This is only used for debugging purposes +inline std::ostream& operator<<(std::ostream& s, std::vector<std::string> const& v) { + int not_first = 0; + for (auto& e : v) s << (not_first++ ? " " : "") << e; + return s; +} + +// Properly quote a string for Powershell: replace ' or " with '' or "" +// FIXME: we should probably get rid of newlines! +// FIXME: the \" sequence seems unsafe, too! +// XXX: this is no longer used but I would like to keep it around just in case +inline std::string internal::dialog::powershell_quote(std::string const& str) const { + return "'" + std::regex_replace(str, std::regex("['\"]"), "$&$&") + "'"; +} + +// Properly quote a string for osascript: replace \ or " with \\ or \" +// XXX: this also used to replace ' with \' when popen was used, but it would be +// smarter to do shell_quote(osascript_quote(...)) if this is needed again. +inline std::string internal::dialog::osascript_quote(std::string const& str) const { + return "\"" + std::regex_replace(str, std::regex("[\\\\\"]"), "\\$&") + "\""; +} + +// Properly quote a string for the shell: just replace ' with '\'' +// XXX: this is no longer used but I would like to keep it around just in case +inline std::string internal::dialog::shell_quote(std::string const& str) const { + return "'" + std::regex_replace(str, std::regex("'"), "'\\''") + "'"; +} + +// file_dialog implementation + +inline internal::file_dialog::file_dialog(type in_type, std::string const& title, + std::string const& default_path /* = "" */, + std::vector<std::string> const& filters /* = {} */, + opt options /* = opt::none */) { #if _WIN32 - std::string filter_list; - std::regex whitespace(" *"); - for (size_t i = 0; i + 1 < filters.size(); i += 2) - { - filter_list += filters[i] + '\0'; - filter_list += std::regex_replace(filters[i + 1], whitespace, ";") + '\0'; - } - filter_list += '\0'; - - m_async->start_func([this, in_type, title, default_path, filter_list, - options](int* exit_code) -> std::string { - (void)exit_code; - m_wtitle = internal::str2wstr(title); - m_wdefault_path = internal::str2wstr(default_path); - auto wfilter_list = internal::str2wstr(filter_list); - - // Initialise COM. This is required for the new folder selection window, - // (see https://github.com/samhocevar/portable-file-dialogs/pull/21) - // and to avoid random crashes with GetOpenFileNameW() (see - // https://github.com/samhocevar/portable-file-dialogs/issues/51) - ole32_dll ole32; - - // Folder selection uses a different method - if (in_type == type::folder) - { + std::string filter_list; + std::regex whitespace(" *"); + for (size_t i = 0; i + 1 < filters.size(); i += 2) { + filter_list += filters[i] + '\0'; + filter_list += std::regex_replace(filters[i + 1], whitespace, ";") + '\0'; + } + filter_list += '\0'; + + m_async->start_func( + [this, in_type, title, default_path, filter_list, options](int* exit_code) -> std::string { + (void) exit_code; + m_wtitle = internal::str2wstr(title); + m_wdefault_path = internal::str2wstr(default_path); + auto wfilter_list = internal::str2wstr(filter_list); + + // Initialise COM. This is required for the new folder selection window, + // (see https://github.com/samhocevar/portable-file-dialogs/pull/21) + // and to avoid random crashes with GetOpenFileNameW() (see + // https://github.com/samhocevar/portable-file-dialogs/issues/51) + ole32_dll ole32; + + // Folder selection uses a different method + if (in_type == type::folder) { #if PFD_HAS_IFILEDIALOG - if (flags(flag::is_vista)) - { - // On Vista and higher we should be able to use IFileDialog for folder selection - IFileDialog* ifd; - HRESULT hr = dll::proc<HRESULT WINAPI(REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID*)>(ole32, "CoCreateInstance")(CLSID_FileOpenDialog, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&ifd)); - - // In case CoCreateInstance fails (which it should not), try legacy approach - if (SUCCEEDED(hr)) - return select_folder_vista(ifd, options & opt::force_path); - } + if (flags(flag::is_vista)) { + // On Vista and higher we should be able to use IFileDialog for folder selection + IFileDialog* ifd; + HRESULT hr = dll::proc<HRESULT WINAPI(REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID*)>( + ole32, "CoCreateInstance")(CLSID_FileOpenDialog, nullptr, CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&ifd)); + + // In case CoCreateInstance fails (which it should not), try legacy approach + if (SUCCEEDED(hr)) return select_folder_vista(ifd, options & opt::force_path); + } #endif - BROWSEINFOW bi; - memset(&bi, 0, sizeof(bi)); - - bi.lpfn = &bffcallback; - bi.lParam = (LPARAM)this; - - if (flags(flag::is_vista)) - { - if (ole32.is_initialized()) - bi.ulFlags |= BIF_NEWDIALOGSTYLE; - bi.ulFlags |= BIF_EDITBOX; - bi.ulFlags |= BIF_STATUSTEXT; - } - - auto* list = SHBrowseForFolderW(&bi); - std::string ret; - if (list) - { - auto buffer = new wchar_t[MAX_PATH]; - SHGetPathFromIDListW(list, buffer); - dll::proc<void WINAPI(LPVOID)>(ole32, "CoTaskMemFree")(list); - ret = internal::wstr2str(buffer); - delete[] buffer; - } - return ret; - } - - OPENFILENAMEW ofn; - memset(&ofn, 0, sizeof(ofn)); - ofn.lStructSize = sizeof(OPENFILENAMEW); - ofn.hwndOwner = GetActiveWindow(); - - ofn.lpstrFilter = wfilter_list.c_str(); - - auto woutput = std::wstring(MAX_PATH * 256, L'\0'); - ofn.lpstrFile = (LPWSTR)woutput.data(); - ofn.nMaxFile = (DWORD)woutput.size(); - if (!m_wdefault_path.empty()) - { - // If a directory was provided, use it as the initial directory. If - // a valid path was provided, use it as the initial file. Otherwise, - // let the Windows API decide. - auto path_attr = GetFileAttributesW(m_wdefault_path.c_str()); - if (path_attr != INVALID_FILE_ATTRIBUTES && (path_attr & FILE_ATTRIBUTE_DIRECTORY)) - ofn.lpstrInitialDir = m_wdefault_path.c_str(); - else if (m_wdefault_path.size() <= woutput.size()) - //second argument is size of buffer, not length of string - StringCchCopyW(ofn.lpstrFile, MAX_PATH * 256 + 1, m_wdefault_path.c_str()); - else - { - ofn.lpstrFileTitle = (LPWSTR)m_wdefault_path.data(); - ofn.nMaxFileTitle = (DWORD)m_wdefault_path.size(); - } - } - ofn.lpstrTitle = m_wtitle.c_str(); - ofn.Flags = OFN_NOCHANGEDIR | OFN_EXPLORER; - - dll comdlg32("comdlg32.dll"); - - // Apply new visual style (required for windows XP) - new_style_context ctx; - - if (in_type == type::save) - { - if (!(options & opt::force_overwrite)) - ofn.Flags |= OFN_OVERWRITEPROMPT; - - dll::proc<BOOL WINAPI(LPOPENFILENAMEW)> get_save_file_name(comdlg32, "GetSaveFileNameW"); - if (get_save_file_name(&ofn) == 0) - return ""; - return internal::wstr2str(woutput.c_str()); - } - else - { - if (options & opt::multiselect) - ofn.Flags |= OFN_ALLOWMULTISELECT; - ofn.Flags |= OFN_PATHMUSTEXIST; - - dll::proc<BOOL WINAPI(LPOPENFILENAMEW)> get_open_file_name(comdlg32, "GetOpenFileNameW"); - if (get_open_file_name(&ofn) == 0) - return ""; - } - - std::string prefix; - for (wchar_t const* p = woutput.c_str(); *p;) - { - auto filename = internal::wstr2str(p); - p += wcslen(p); - // In multiselect mode, we advance p one wchar further and - // check for another filename. If there is one and the - // prefix is empty, it means we just read the prefix. - if ((options & opt::multiselect) && *++p && prefix.empty()) - { - prefix = filename + "/"; - continue; - } - - m_vector_result.push_back(prefix + filename); - } - - return ""; - }); + BROWSEINFOW bi; + memset(&bi, 0, sizeof(bi)); + + bi.lpfn = &bffcallback; + bi.lParam = (LPARAM) this; + + if (flags(flag::is_vista)) { + if (ole32.is_initialized()) bi.ulFlags |= BIF_NEWDIALOGSTYLE; + bi.ulFlags |= BIF_EDITBOX; + bi.ulFlags |= BIF_STATUSTEXT; + } + + auto* list = SHBrowseForFolderW(&bi); + std::string ret; + if (list) { + auto buffer = new wchar_t[MAX_PATH]; + SHGetPathFromIDListW(list, buffer); + dll::proc<void WINAPI(LPVOID)>(ole32, "CoTaskMemFree")(list); + ret = internal::wstr2str(buffer); + delete[] buffer; + } + return ret; + } + + OPENFILENAMEW ofn; + memset(&ofn, 0, sizeof(ofn)); + ofn.lStructSize = sizeof(OPENFILENAMEW); + ofn.hwndOwner = GetActiveWindow(); + + ofn.lpstrFilter = wfilter_list.c_str(); + + auto woutput = std::wstring(MAX_PATH * 256, L'\0'); + ofn.lpstrFile = (LPWSTR) woutput.data(); + ofn.nMaxFile = (DWORD) woutput.size(); + if (!m_wdefault_path.empty()) { + // If a directory was provided, use it as the initial directory. If + // a valid path was provided, use it as the initial file. Otherwise, + // let the Windows API decide. + auto path_attr = GetFileAttributesW(m_wdefault_path.c_str()); + if (path_attr != INVALID_FILE_ATTRIBUTES && (path_attr & FILE_ATTRIBUTE_DIRECTORY)) + ofn.lpstrInitialDir = m_wdefault_path.c_str(); + else if (m_wdefault_path.size() <= woutput.size()) + // second argument is size of buffer, not length of string + StringCchCopyW(ofn.lpstrFile, MAX_PATH * 256 + 1, m_wdefault_path.c_str()); + else { + ofn.lpstrFileTitle = (LPWSTR) m_wdefault_path.data(); + ofn.nMaxFileTitle = (DWORD) m_wdefault_path.size(); + } + } + ofn.lpstrTitle = m_wtitle.c_str(); + ofn.Flags = OFN_NOCHANGEDIR | OFN_EXPLORER; + + dll comdlg32("comdlg32.dll"); + + // Apply new visual style (required for windows XP) + new_style_context ctx; + + if (in_type == type::save) { + if (!(options & opt::force_overwrite)) ofn.Flags |= OFN_OVERWRITEPROMPT; + + dll::proc<BOOL WINAPI(LPOPENFILENAMEW)> get_save_file_name(comdlg32, "GetSaveFileNameW"); + if (get_save_file_name(&ofn) == 0) return ""; + return internal::wstr2str(woutput.c_str()); + } else { + if (options & opt::multiselect) ofn.Flags |= OFN_ALLOWMULTISELECT; + ofn.Flags |= OFN_PATHMUSTEXIST; + + dll::proc<BOOL WINAPI(LPOPENFILENAMEW)> get_open_file_name(comdlg32, "GetOpenFileNameW"); + if (get_open_file_name(&ofn) == 0) return ""; + } + + std::string prefix; + for (wchar_t const* p = woutput.c_str(); *p;) { + auto filename = internal::wstr2str(p); + p += wcslen(p); + // In multiselect mode, we advance p one wchar further and + // check for another filename. If there is one and the + // prefix is empty, it means we just read the prefix. + if ((options & opt::multiselect) && *++p && prefix.empty()) { + prefix = filename + "/"; + continue; + } + + m_vector_result.push_back(prefix + filename); + } + + return ""; + }); #elif __EMSCRIPTEN__ - // FIXME: do something - (void)in_type; - (void)title; - (void)default_path; - (void)filters; - (void)options; + // FIXME: do something + (void) in_type; + (void) title; + (void) default_path; + (void) filters; + (void) options; #else - auto command = desktop_helper(); - - if (is_osascript()) - { - std::string script = "set ret to choose"; - switch (in_type) - { - case type::save: - script += " file name"; - break; - case type::open: - default: - script += " file"; - if (options & opt::multiselect) - script += " with multiple selections allowed"; - break; - case type::folder: - script += " folder"; - break; - } - - if (default_path.size()) - { - if (in_type == type::folder || is_directory(default_path)) - script += " default location "; - else - script += " default name "; - script += osascript_quote(default_path); - } - - script += " with prompt " + osascript_quote(title); - - if (in_type == type::open) - { - // Concatenate all user-provided filter patterns - std::string patterns; - for (size_t i = 0; i < filters.size() / 2; ++i) - patterns += " " + filters[2 * i + 1]; - - // Split the pattern list to check whether "*" is in there; if it - // is, we have to disable filters because there is no mechanism in - // OS X for the user to override the filter. - std::regex sep("\\s+"); - std::string filter_list; - bool has_filter = true; - std::sregex_token_iterator iter(patterns.begin(), patterns.end(), sep, -1); - std::sregex_token_iterator end; - for (; iter != end; ++iter) - { - auto pat = iter->str(); - if (pat == "*" || pat == "*.*") - has_filter = false; - else if (internal::starts_with(pat, "*.")) - filter_list += "," + osascript_quote(pat.substr(2, pat.size() - 2)); - } - - if (has_filter && filter_list.size() > 0) - { - // There is a weird AppleScript bug where file extensions of length != 3 are - // ignored, e.g. type{"txt"} works, but type{"json"} does not. Fortunately if - // the whole list starts with a 3-character extension, everything works again. - // We use "///" for such an extension because we are sure it cannot appear in - // an actual filename. - script += " of type {\"///\"" + filter_list + "}"; - } - } - - if (in_type == type::open && (options & opt::multiselect)) - { - script += "\nset s to \"\""; - script += "\nrepeat with i in ret"; - script += "\n set s to s & (POSIX path of i) & \"\\n\""; - script += "\nend repeat"; - script += "\ncopy s to stdout"; - } - else - { - script += "\nPOSIX path of ret"; - } - - command.push_back("-e"); - command.push_back(script); - } - else if (is_zenity()) - { - command.push_back("--file-selection"); - - // If the default path is a directory, make sure it ends with "/" otherwise zenity will - // open the file dialog in the parent directory. - auto filename_arg = "--filename=" + default_path; - if (in_type != type::folder && !ends_with(default_path, "/") && internal::is_directory(default_path)) - filename_arg += "/"; - command.push_back(filename_arg); - - command.push_back("--title"); - command.push_back(title); - command.push_back("--separator=\n"); - - for (size_t i = 0; i < filters.size() / 2; ++i) - { - command.push_back("--file-filter"); - command.push_back(filters[2 * i] + "|" + filters[2 * i + 1]); - } - - if (in_type == type::save) - command.push_back("--save"); - if (in_type == type::folder) - command.push_back("--directory"); - if (!(options & opt::force_overwrite)) - command.push_back("--confirm-overwrite"); - if (options & opt::multiselect) - command.push_back("--multiple"); - } - else if (is_kdialog()) - { - switch (in_type) - { - case type::save: - command.push_back("--getsavefilename"); - break; - case type::open: - command.push_back("--getopenfilename"); - break; - case type::folder: - command.push_back("--getexistingdirectory"); - break; - } - if (options & opt::multiselect) - { - command.push_back("--multiple"); - command.push_back("--separate-output"); - } - - command.push_back(default_path); - - std::string filter; - for (size_t i = 0; i < filters.size() / 2; ++i) - filter += (i == 0 ? "" : " | ") + filters[2 * i] + "(" + filters[2 * i + 1] + ")"; - command.push_back(filter); - - command.push_back("--title"); - command.push_back(title); - } - - if (flags(flag::is_verbose)) - std::cerr << "pfd: " << command << std::endl; - - m_async->start_process(command); + auto command = desktop_helper(); + + if (is_osascript()) { + std::string script = "set ret to choose"; + switch (in_type) { + case type::save: + script += " file name"; + break; + case type::open: + default: + script += " file"; + if (options & opt::multiselect) script += " with multiple selections allowed"; + break; + case type::folder: + script += " folder"; + break; + } + + if (default_path.size()) { + if (in_type == type::folder || is_directory(default_path)) + script += " default location "; + else + script += " default name "; + script += osascript_quote(default_path); + } + + script += " with prompt " + osascript_quote(title); + + if (in_type == type::open) { + // Concatenate all user-provided filter patterns + std::string patterns; + for (size_t i = 0; i < filters.size() / 2; ++i) patterns += " " + filters[2 * i + 1]; + + // Split the pattern list to check whether "*" is in there; if it + // is, we have to disable filters because there is no mechanism in + // OS X for the user to override the filter. + std::regex sep("\\s+"); + std::string filter_list; + bool has_filter = true; + std::sregex_token_iterator iter(patterns.begin(), patterns.end(), sep, -1); + std::sregex_token_iterator end; + for (; iter != end; ++iter) { + auto pat = iter->str(); + if (pat == "*" || pat == "*.*") + has_filter = false; + else if (internal::starts_with(pat, "*.")) + filter_list += "," + osascript_quote(pat.substr(2, pat.size() - 2)); + } + + if (has_filter && filter_list.size() > 0) { + // There is a weird AppleScript bug where file extensions of length != 3 are + // ignored, e.g. type{"txt"} works, but type{"json"} does not. Fortunately if + // the whole list starts with a 3-character extension, everything works again. + // We use "///" for such an extension because we are sure it cannot appear in + // an actual filename. + script += " of type {\"///\"" + filter_list + "}"; + } + } + + if (in_type == type::open && (options & opt::multiselect)) { + script += "\nset s to \"\""; + script += "\nrepeat with i in ret"; + script += "\n set s to s & (POSIX path of i) & \"\\n\""; + script += "\nend repeat"; + script += "\ncopy s to stdout"; + } else { + script += "\nPOSIX path of ret"; + } + + command.push_back("-e"); + command.push_back(script); + } else if (is_zenity()) { + command.push_back("--file-selection"); + + // If the default path is a directory, make sure it ends with "/" otherwise zenity will + // open the file dialog in the parent directory. + auto filename_arg = "--filename=" + default_path; + if (in_type != type::folder && !ends_with(default_path, "/") && + internal::is_directory(default_path)) + filename_arg += "/"; + command.push_back(filename_arg); + + command.push_back("--title"); + command.push_back(title); + command.push_back("--separator=\n"); + + for (size_t i = 0; i < filters.size() / 2; ++i) { + command.push_back("--file-filter"); + command.push_back(filters[2 * i] + "|" + filters[2 * i + 1]); + } + + if (in_type == type::save) command.push_back("--save"); + if (in_type == type::folder) command.push_back("--directory"); + if (!(options & opt::force_overwrite)) command.push_back("--confirm-overwrite"); + if (options & opt::multiselect) command.push_back("--multiple"); + } else if (is_kdialog()) { + switch (in_type) { + case type::save: + command.push_back("--getsavefilename"); + break; + case type::open: + command.push_back("--getopenfilename"); + break; + case type::folder: + command.push_back("--getexistingdirectory"); + break; + } + if (options & opt::multiselect) { + command.push_back("--multiple"); + command.push_back("--separate-output"); + } + + command.push_back(default_path); + + std::string filter; + for (size_t i = 0; i < filters.size() / 2; ++i) + filter += (i == 0 ? "" : " | ") + filters[2 * i] + "(" + filters[2 * i + 1] + ")"; + command.push_back(filter); + + command.push_back("--title"); + command.push_back(title); + } + + if (flags(flag::is_verbose)) std::cerr << "pfd: " << command << std::endl; + + m_async->start_process(command); #endif - } +} - inline std::string internal::file_dialog::string_result() - { +inline std::string internal::file_dialog::string_result() { #if _WIN32 - return m_async->result(); + return m_async->result(); #else - auto ret = m_async->result(); - // Strip potential trailing newline (zenity). Also strip trailing slash - // added by osascript for consistency with other backends. - while (!ret.empty() && (ret.back() == '\n' || ret.back() == '/')) - ret.pop_back(); - return ret; + auto ret = m_async->result(); + // Strip potential trailing newline (zenity). Also strip trailing slash + // added by osascript for consistency with other backends. + while (!ret.empty() && (ret.back() == '\n' || ret.back() == '/')) ret.pop_back(); + return ret; #endif - } +} - inline std::vector<std::string> internal::file_dialog::vector_result() - { +inline std::vector<std::string> internal::file_dialog::vector_result() { #if _WIN32 - m_async->result(); - return m_vector_result; + m_async->result(); + return m_vector_result; #else - std::vector<std::string> ret; - auto result = m_async->result(); - for (;;) - { - // Split result along newline characters - auto i = result.find('\n'); - if (i == 0 || i == std::string::npos) - break; - ret.push_back(result.substr(0, i)); - result = result.substr(i + 1, result.size()); - } - return ret; + std::vector<std::string> ret; + auto result = m_async->result(); + for (;;) { + // Split result along newline characters + auto i = result.find('\n'); + if (i == 0 || i == std::string::npos) break; + ret.push_back(result.substr(0, i)); + result = result.substr(i + 1, result.size()); + } + return ret; #endif - } +} #if _WIN32 - // Use a static function to pass as BFFCALLBACK for legacy folder select - inline int CALLBACK internal::file_dialog::bffcallback(HWND hwnd, UINT uMsg, LPARAM, LPARAM pData) - { - auto inst = (file_dialog*)pData; - switch (uMsg) - { - case BFFM_INITIALIZED: - SendMessage(hwnd, BFFM_SETSELECTIONW, TRUE, (LPARAM)inst->m_wdefault_path.c_str()); - break; - } - return 0; - } +// Use a static function to pass as BFFCALLBACK for legacy folder select +inline int CALLBACK internal::file_dialog::bffcallback(HWND hwnd, UINT uMsg, LPARAM, LPARAM pData) { + auto inst = (file_dialog*) pData; + switch (uMsg) { + case BFFM_INITIALIZED: + SendMessage(hwnd, BFFM_SETSELECTIONW, TRUE, (LPARAM) inst->m_wdefault_path.c_str()); + break; + } + return 0; +} #if PFD_HAS_IFILEDIALOG - inline std::string internal::file_dialog::select_folder_vista(IFileDialog* ifd, bool force_path) - { - std::string result; - - IShellItem* folder; - - // Load library at runtime so app doesn't link it at load time (which will fail on windows XP) - dll shell32("shell32.dll"); - dll::proc<HRESULT WINAPI(PCWSTR, IBindCtx*, REFIID, void**)> - create_item(shell32, "SHCreateItemFromParsingName"); - - if (!create_item) - return ""; - - auto hr = create_item(m_wdefault_path.c_str(), - nullptr, - IID_PPV_ARGS(&folder)); - - // Set default folder if found. This only sets the default folder. If - // Windows has any info about the most recently selected folder, it - // will display it instead. Generally, calling SetFolder() to set the - // current directory “is not a good or expected user experience and - // should therefore be avoided”: - // https://docs.microsoft.com/windows/win32/api/shobjidl_core/nf-shobjidl_core-ifiledialog-setfolder - if (SUCCEEDED(hr)) - { - if (force_path) - ifd->SetFolder(folder); - else - ifd->SetDefaultFolder(folder); - folder->Release(); - } - - // Set the dialog title and option to select folders - ifd->SetOptions(FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM); - ifd->SetTitle(m_wtitle.c_str()); - - hr = ifd->Show(GetActiveWindow()); - if (SUCCEEDED(hr)) - { - IShellItem* item; - hr = ifd->GetResult(&item); - if (SUCCEEDED(hr)) - { - wchar_t* wname = nullptr; - // This is unlikely to fail because we use FOS_FORCEFILESYSTEM, but try - // to output a debug message just in case. - if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &wname))) - { - result = internal::wstr2str(std::wstring(wname)); - dll::proc<void WINAPI(LPVOID)>(ole32_dll(), "CoTaskMemFree")(wname); - } - else - { - if (SUCCEEDED(item->GetDisplayName(SIGDN_NORMALDISPLAY, &wname))) - { - auto name = internal::wstr2str(std::wstring(wname)); - dll::proc<void WINAPI(LPVOID)>(ole32_dll(), "CoTaskMemFree")(wname); - std::cerr << "pfd: failed to get path for " << name << std::endl; - } - else - std::cerr << "pfd: item of unknown type selected" << std::endl; - } - - item->Release(); - } - } - - ifd->Release(); - - return result; - } +inline std::string internal::file_dialog::select_folder_vista(IFileDialog* ifd, bool force_path) { + std::string result; + + IShellItem* folder; + + // Load library at runtime so app doesn't link it at load time (which will fail on windows XP) + dll shell32("shell32.dll"); + dll::proc<HRESULT WINAPI(PCWSTR, IBindCtx*, REFIID, void**)> create_item( + shell32, "SHCreateItemFromParsingName"); + + if (!create_item) return ""; + + auto hr = create_item(m_wdefault_path.c_str(), nullptr, IID_PPV_ARGS(&folder)); + + // Set default folder if found. This only sets the default folder. If + // Windows has any info about the most recently selected folder, it + // will display it instead. Generally, calling SetFolder() to set the + // current directory “is not a good or expected user experience and + // should therefore be avoided”: + // https://docs.microsoft.com/windows/win32/api/shobjidl_core/nf-shobjidl_core-ifiledialog-setfolder + if (SUCCEEDED(hr)) { + if (force_path) + ifd->SetFolder(folder); + else + ifd->SetDefaultFolder(folder); + folder->Release(); + } + + // Set the dialog title and option to select folders + ifd->SetOptions(FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM); + ifd->SetTitle(m_wtitle.c_str()); + + hr = ifd->Show(GetActiveWindow()); + if (SUCCEEDED(hr)) { + IShellItem* item; + hr = ifd->GetResult(&item); + if (SUCCEEDED(hr)) { + wchar_t* wname = nullptr; + // This is unlikely to fail because we use FOS_FORCEFILESYSTEM, but try + // to output a debug message just in case. + if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &wname))) { + result = internal::wstr2str(std::wstring(wname)); + dll::proc<void WINAPI(LPVOID)>(ole32_dll(), "CoTaskMemFree")(wname); + } else { + if (SUCCEEDED(item->GetDisplayName(SIGDN_NORMALDISPLAY, &wname))) { + auto name = internal::wstr2str(std::wstring(wname)); + dll::proc<void WINAPI(LPVOID)>(ole32_dll(), "CoTaskMemFree")(wname); + std::cerr << "pfd: failed to get path for " << name << std::endl; + } else + std::cerr << "pfd: item of unknown type selected" << std::endl; + } + + item->Release(); + } + } + + ifd->Release(); + + return result; +} #endif #endif - // notify implementation +// notify implementation - inline notify::notify(std::string const& title, - std::string const& message, - icon _icon /* = icon::info */) - { - if (_icon == icon::question) // Not supported by notifications - _icon = icon::info; +inline notify::notify(std::string const& title, std::string const& message, + icon _icon /* = icon::info */) { + if (_icon == icon::question) // Not supported by notifications + _icon = icon::info; #if _WIN32 - // Use a static shared pointer for notify_icon so that we can delete - // it whenever we need to display a new one, and we can also wait - // until the program has finished running. - struct notify_icon_data : public NOTIFYICONDATAW - { - ~notify_icon_data() - { - Shell_NotifyIconW(NIM_DELETE, this); - } - }; - - static std::shared_ptr<notify_icon_data> nid; - - // Release the previous notification icon, if any, and allocate a new - // one. Note that std::make_shared() does value initialization, so there - // is no need to memset the structure. - nid = nullptr; - nid = std::make_shared<notify_icon_data>(); - - // For XP support - nid->cbSize = NOTIFYICONDATAW_V2_SIZE; - nid->hWnd = nullptr; - nid->uID = 0; - - // Flag Description: - // - NIF_ICON The hIcon member is valid. - // - NIF_MESSAGE The uCallbackMessage member is valid. - // - NIF_TIP The szTip member is valid. - // - NIF_STATE The dwState and dwStateMask members are valid. - // - NIF_INFO Use a balloon ToolTip instead of a standard ToolTip. The szInfo, uTimeout, szInfoTitle, and dwInfoFlags members are valid. - // - NIF_GUID Reserved. - nid->uFlags = NIF_MESSAGE | NIF_ICON | NIF_INFO; - - // Flag Description - // - NIIF_ERROR An error icon. - // - NIIF_INFO An information icon. - // - NIIF_NONE No icon. - // - NIIF_WARNING A warning icon. - // - NIIF_ICON_MASK Version 6.0. Reserved. - // - NIIF_NOSOUND Version 6.0. Do not play the associated sound. Applies only to balloon ToolTips - switch (_icon) - { - case icon::warning: - nid->dwInfoFlags = NIIF_WARNING; - break; - case icon::error: - nid->dwInfoFlags = NIIF_ERROR; - break; - /* case icon::info: */ default: - nid->dwInfoFlags = NIIF_INFO; - break; - } - - ENUMRESNAMEPROC icon_enum_callback = [](HMODULE, LPCTSTR, LPTSTR lpName, LONG_PTR lParam) -> BOOL { - ((NOTIFYICONDATAW*)lParam)->hIcon = ::LoadIcon(GetModuleHandle(nullptr), lpName); - return false; - }; - - nid->hIcon = ::LoadIcon(nullptr, IDI_APPLICATION); - ::EnumResourceNames(nullptr, RT_GROUP_ICON, icon_enum_callback, (LONG_PTR)nid.get()); - - nid->uTimeout = 5000; - - StringCchCopyW(nid->szInfoTitle, ARRAYSIZE(nid->szInfoTitle), internal::str2wstr(title).c_str()); - StringCchCopyW(nid->szInfo, ARRAYSIZE(nid->szInfo), internal::str2wstr(message).c_str()); - - // Display the new icon - Shell_NotifyIconW(NIM_ADD, nid.get()); + // Use a static shared pointer for notify_icon so that we can delete + // it whenever we need to display a new one, and we can also wait + // until the program has finished running. + struct notify_icon_data : public NOTIFYICONDATAW { + ~notify_icon_data() { Shell_NotifyIconW(NIM_DELETE, this); } + }; + + static std::shared_ptr<notify_icon_data> nid; + + // Release the previous notification icon, if any, and allocate a new + // one. Note that std::make_shared() does value initialization, so there + // is no need to memset the structure. + nid = nullptr; + nid = std::make_shared<notify_icon_data>(); + + // For XP support + nid->cbSize = NOTIFYICONDATAW_V2_SIZE; + nid->hWnd = nullptr; + nid->uID = 0; + + // Flag Description: + // - NIF_ICON The hIcon member is valid. + // - NIF_MESSAGE The uCallbackMessage member is valid. + // - NIF_TIP The szTip member is valid. + // - NIF_STATE The dwState and dwStateMask members are valid. + // - NIF_INFO Use a balloon ToolTip instead of a standard ToolTip. The szInfo, uTimeout, + // szInfoTitle, and dwInfoFlags members are valid. + // - NIF_GUID Reserved. + nid->uFlags = NIF_MESSAGE | NIF_ICON | NIF_INFO; + + // Flag Description + // - NIIF_ERROR An error icon. + // - NIIF_INFO An information icon. + // - NIIF_NONE No icon. + // - NIIF_WARNING A warning icon. + // - NIIF_ICON_MASK Version 6.0. Reserved. + // - NIIF_NOSOUND Version 6.0. Do not play the associated sound. Applies only to balloon + // ToolTips + switch (_icon) { + case icon::warning: + nid->dwInfoFlags = NIIF_WARNING; + break; + case icon::error: + nid->dwInfoFlags = NIIF_ERROR; + break; + /* case icon::info: */ default: + nid->dwInfoFlags = NIIF_INFO; + break; + } + + ENUMRESNAMEPROC icon_enum_callback = [](HMODULE, LPCTSTR, LPTSTR lpName, + LONG_PTR lParam) -> BOOL { + ((NOTIFYICONDATAW*) lParam)->hIcon = ::LoadIcon(GetModuleHandle(nullptr), lpName); + return false; + }; + + nid->hIcon = ::LoadIcon(nullptr, IDI_APPLICATION); + ::EnumResourceNames(nullptr, RT_GROUP_ICON, icon_enum_callback, (LONG_PTR) nid.get()); + + nid->uTimeout = 5000; + + StringCchCopyW(nid->szInfoTitle, ARRAYSIZE(nid->szInfoTitle), internal::str2wstr(title).c_str()); + StringCchCopyW(nid->szInfo, ARRAYSIZE(nid->szInfo), internal::str2wstr(message).c_str()); + + // Display the new icon + Shell_NotifyIconW(NIM_ADD, nid.get()); #elif __EMSCRIPTEN__ - // FIXME: do something - (void)title; - (void)message; + // FIXME: do something + (void) title; + (void) message; #else - auto command = desktop_helper(); - - if (is_osascript()) - { - command.push_back("-e"); - command.push_back("display notification " + osascript_quote(message) + - " with title " + osascript_quote(title)); - } - else if (is_zenity()) - { - command.push_back("--notification"); - command.push_back("--window-icon"); - command.push_back(get_icon_name(_icon)); - command.push_back("--text"); - command.push_back(title + "\n" + message); - } - else if (is_kdialog()) - { - command.push_back("--icon"); - command.push_back(get_icon_name(_icon)); - command.push_back("--title"); - command.push_back(title); - command.push_back("--passivepopup"); - command.push_back(message); - command.push_back("5"); - } - - if (flags(flag::is_verbose)) - std::cerr << "pfd: " << command << std::endl; - - m_async->start_process(command); + auto command = desktop_helper(); + + if (is_osascript()) { + command.push_back("-e"); + command.push_back("display notification " + osascript_quote(message) + " with title " + + osascript_quote(title)); + } else if (is_zenity()) { + command.push_back("--notification"); + command.push_back("--window-icon"); + command.push_back(get_icon_name(_icon)); + command.push_back("--text"); + command.push_back(title + "\n" + message); + } else if (is_kdialog()) { + command.push_back("--icon"); + command.push_back(get_icon_name(_icon)); + command.push_back("--title"); + command.push_back(title); + command.push_back("--passivepopup"); + command.push_back(message); + command.push_back("5"); + } + + if (flags(flag::is_verbose)) std::cerr << "pfd: " << command << std::endl; + + m_async->start_process(command); #endif - } +} - // message implementation +// message implementation - inline message::message(std::string const& title, - std::string const& text, - choice _choice /* = choice::ok_cancel */, - icon _icon /* = icon::info */) - { +inline message::message(std::string const& title, std::string const& text, + choice _choice /* = choice::ok_cancel */, icon _icon /* = icon::info */) { #if _WIN32 - // Use MB_SYSTEMMODAL rather than MB_TOPMOST to ensure the message window is brought - // to front. See https://github.com/samhocevar/portable-file-dialogs/issues/52 - UINT style = MB_SYSTEMMODAL; - switch (_icon) - { - case icon::warning: - style |= MB_ICONWARNING; - break; - case icon::error: - style |= MB_ICONERROR; - break; - case icon::question: - style |= MB_ICONQUESTION; - break; - /* case icon::info: */ default: - style |= MB_ICONINFORMATION; - break; - } - - switch (_choice) - { - case choice::ok_cancel: - style |= MB_OKCANCEL; - break; - case choice::yes_no: - style |= MB_YESNO; - break; - case choice::yes_no_cancel: - style |= MB_YESNOCANCEL; - break; - case choice::retry_cancel: - style |= MB_RETRYCANCEL; - break; - case choice::abort_retry_ignore: - style |= MB_ABORTRETRYIGNORE; - break; - /* case choice::ok: */ default: - style |= MB_OK; - break; - } - - m_mappings[IDCANCEL] = button::cancel; - m_mappings[IDOK] = button::ok; - m_mappings[IDYES] = button::yes; - m_mappings[IDNO] = button::no; - m_mappings[IDABORT] = button::abort; - m_mappings[IDRETRY] = button::retry; - m_mappings[IDIGNORE] = button::ignore; - - m_async->start_func([text, title, style](int* exit_code) -> std::string { - auto wtext = internal::str2wstr(text); - auto wtitle = internal::str2wstr(title); - // Apply new visual style (required for all Windows versions) - new_style_context ctx; - *exit_code = MessageBoxW(GetActiveWindow(), wtext.c_str(), wtitle.c_str(), style); - return ""; - }); + // Use MB_SYSTEMMODAL rather than MB_TOPMOST to ensure the message window is brought + // to front. See https://github.com/samhocevar/portable-file-dialogs/issues/52 + UINT style = MB_SYSTEMMODAL; + switch (_icon) { + case icon::warning: + style |= MB_ICONWARNING; + break; + case icon::error: + style |= MB_ICONERROR; + break; + case icon::question: + style |= MB_ICONQUESTION; + break; + /* case icon::info: */ default: + style |= MB_ICONINFORMATION; + break; + } + + switch (_choice) { + case choice::ok_cancel: + style |= MB_OKCANCEL; + break; + case choice::yes_no: + style |= MB_YESNO; + break; + case choice::yes_no_cancel: + style |= MB_YESNOCANCEL; + break; + case choice::retry_cancel: + style |= MB_RETRYCANCEL; + break; + case choice::abort_retry_ignore: + style |= MB_ABORTRETRYIGNORE; + break; + /* case choice::ok: */ default: + style |= MB_OK; + break; + } + + m_mappings[IDCANCEL] = button::cancel; + m_mappings[IDOK] = button::ok; + m_mappings[IDYES] = button::yes; + m_mappings[IDNO] = button::no; + m_mappings[IDABORT] = button::abort; + m_mappings[IDRETRY] = button::retry; + m_mappings[IDIGNORE] = button::ignore; + + m_async->start_func([text, title, style](int* exit_code) -> std::string { + auto wtext = internal::str2wstr(text); + auto wtitle = internal::str2wstr(title); + // Apply new visual style (required for all Windows versions) + new_style_context ctx; + *exit_code = MessageBoxW(GetActiveWindow(), wtext.c_str(), wtitle.c_str(), style); + return ""; + }); #elif __EMSCRIPTEN__ - std::string full_message; - switch (_icon) - { - case icon::warning: - full_message = "⚠️"; - break; - case icon::error: - full_message = "⛔"; - break; - case icon::question: - full_message = "❓"; - break; - /* case icon::info: */ default: - full_message = "ℹ"; - break; - } - - full_message += ' ' + title + "\n\n" + text; - - // This does not really start an async task; it just passes the - // EM_ASM_INT return value to a fake start() function. - m_async->start(EM_ASM_INT( - { - if ($1) - return window.confirm(UTF8ToString($0)) ? 0 : -1; - alert(UTF8ToString($0)); - return 0; - }, - full_message.c_str(), _choice == choice::ok_cancel)); + std::string full_message; + switch (_icon) { + case icon::warning: + full_message = "⚠️"; + break; + case icon::error: + full_message = "⛔"; + break; + case icon::question: + full_message = "❓"; + break; + /* case icon::info: */ default: + full_message = "ℹ"; + break; + } + + full_message += ' ' + title + "\n\n" + text; + + // This does not really start an async task; it just passes the + // EM_ASM_INT return value to a fake start() function. + m_async->start(EM_ASM_INT( + { + if ($1) return window.confirm(UTF8ToString($0)) ? 0 : -1; + alert(UTF8ToString($0)); + return 0; + }, + full_message.c_str(), _choice == choice::ok_cancel)); #else - auto command = desktop_helper(); - - if (is_osascript()) - { - std::string script = "display dialog " + osascript_quote(text) + - " with title " + osascript_quote(title); - auto if_cancel = button::cancel; - switch (_choice) - { - case choice::ok_cancel: - script += "buttons {\"OK\", \"Cancel\"}" - " default button \"OK\"" - " cancel button \"Cancel\""; - break; - case choice::yes_no: - script += "buttons {\"Yes\", \"No\"}" - " default button \"Yes\"" - " cancel button \"No\""; - if_cancel = button::no; - break; - case choice::yes_no_cancel: - script += "buttons {\"Yes\", \"No\", \"Cancel\"}" - " default button \"Yes\"" - " cancel button \"Cancel\""; - break; - case choice::retry_cancel: - script += "buttons {\"Retry\", \"Cancel\"}" - " default button \"Retry\"" - " cancel button \"Cancel\""; - break; - case choice::abort_retry_ignore: - script += "buttons {\"Abort\", \"Retry\", \"Ignore\"}" - " default button \"Abort\"" - " cancel button \"Retry\""; - if_cancel = button::retry; - break; - case choice::ok: - default: - script += "buttons {\"OK\"}" - " default button \"OK\"" - " cancel button \"OK\""; - if_cancel = button::ok; - break; - } - m_mappings[1] = if_cancel; - m_mappings[256] = if_cancel; // XXX: I think this was never correct - script += " with icon "; - switch (_icon) - { -#define PFD_OSX_ICON(n) "alias ((path to library folder from system domain) as text " \ - "& \"CoreServices:CoreTypes.bundle:Contents:Resources:" n ".icns\")" - case icon::info: - default: - script += PFD_OSX_ICON("ToolBarInfo"); - break; - case icon::warning: - script += "caution"; - break; - case icon::error: - script += "stop"; - break; - case icon::question: - script += PFD_OSX_ICON("GenericQuestionMarkIcon"); - break; + auto command = desktop_helper(); + + if (is_osascript()) { + std::string script = + "display dialog " + osascript_quote(text) + " with title " + osascript_quote(title); + auto if_cancel = button::cancel; + switch (_choice) { + case choice::ok_cancel: + script += + "buttons {\"OK\", \"Cancel\"}" + " default button \"OK\"" + " cancel button \"Cancel\""; + break; + case choice::yes_no: + script += + "buttons {\"Yes\", \"No\"}" + " default button \"Yes\"" + " cancel button \"No\""; + if_cancel = button::no; + break; + case choice::yes_no_cancel: + script += + "buttons {\"Yes\", \"No\", \"Cancel\"}" + " default button \"Yes\"" + " cancel button \"Cancel\""; + break; + case choice::retry_cancel: + script += + "buttons {\"Retry\", \"Cancel\"}" + " default button \"Retry\"" + " cancel button \"Cancel\""; + break; + case choice::abort_retry_ignore: + script += + "buttons {\"Abort\", \"Retry\", \"Ignore\"}" + " default button \"Abort\"" + " cancel button \"Retry\""; + if_cancel = button::retry; + break; + case choice::ok: + default: + script += + "buttons {\"OK\"}" + " default button \"OK\"" + " cancel button \"OK\""; + if_cancel = button::ok; + break; + } + m_mappings[1] = if_cancel; + m_mappings[256] = if_cancel; // XXX: I think this was never correct + script += " with icon "; + switch (_icon) { +#define PFD_OSX_ICON(n) \ + "alias ((path to library folder from system domain) as text " \ + "& \"CoreServices:CoreTypes.bundle:Contents:Resources:" n ".icns\")" + case icon::info: + default: + script += PFD_OSX_ICON("ToolBarInfo"); + break; + case icon::warning: + script += "caution"; + break; + case icon::error: + script += "stop"; + break; + case icon::question: + script += PFD_OSX_ICON("GenericQuestionMarkIcon"); + break; #undef PFD_OSX_ICON - } - - command.push_back("-e"); - command.push_back(script); - } - else if (is_zenity()) - { - switch (_choice) - { - case choice::ok_cancel: - command.insert(command.end(), {"--question", "--cancel-label=Cancel", "--ok-label=OK"}); - break; - case choice::yes_no: - // Do not use standard --question because it causes “No” to return -1, - // which is inconsistent with the “Yes/No/Cancel” mode below. - command.insert(command.end(), {"--question", "--switch", "--extra-button=No", "--extra-button=Yes"}); - break; - case choice::yes_no_cancel: - command.insert(command.end(), {"--question", "--switch", "--extra-button=Cancel", "--extra-button=No", "--extra-button=Yes"}); - break; - case choice::retry_cancel: - command.insert(command.end(), {"--question", "--switch", "--extra-button=Cancel", "--extra-button=Retry"}); - break; - case choice::abort_retry_ignore: - command.insert(command.end(), {"--question", "--switch", "--extra-button=Ignore", "--extra-button=Abort", "--extra-button=Retry"}); - break; - case choice::ok: - default: - switch (_icon) - { - case icon::error: - command.push_back("--error"); - break; - case icon::warning: - command.push_back("--warning"); - break; - default: - command.push_back("--info"); - break; - } - } - - command.insert(command.end(), {"--title", title, - "--width=300", "--height=0", // sensible defaults - "--no-markup", // do not interpret text as Pango markup - "--text", text, - "--icon-name=dialog-" + get_icon_name(_icon)}); - } - else if (is_kdialog()) - { - if (_choice == choice::ok) - { - switch (_icon) - { - case icon::error: - command.push_back("--error"); - break; - case icon::warning: - command.push_back("--sorry"); - break; - default: - command.push_back("--msgbox"); - break; - } - } - else - { - std::string flag = "--"; - if (_icon == icon::warning || _icon == icon::error) - flag += "warning"; - flag += "yesno"; - if (_choice == choice::yes_no_cancel) - flag += "cancel"; - command.push_back(flag); - if (_choice == choice::yes_no || _choice == choice::yes_no_cancel) - { - m_mappings[0] = button::yes; - m_mappings[256] = button::no; - } - } - - command.push_back(text); - command.push_back("--title"); - command.push_back(title); - - // Must be after the above part - if (_choice == choice::ok_cancel) - command.insert(command.end(), {"--yes-label", "OK", "--no-label", "Cancel"}); - } - - if (flags(flag::is_verbose)) - std::cerr << "pfd: " << command << std::endl; - - m_async->start_process(command); + } + + command.push_back("-e"); + command.push_back(script); + } else if (is_zenity()) { + switch (_choice) { + case choice::ok_cancel: + command.insert(command.end(), {"--question", "--cancel-label=Cancel", "--ok-label=OK"}); + break; + case choice::yes_no: + // Do not use standard --question because it causes “No” to return -1, + // which is inconsistent with the “Yes/No/Cancel” mode below. + command.insert(command.end(), + {"--question", "--switch", "--extra-button=No", "--extra-button=Yes"}); + break; + case choice::yes_no_cancel: + command.insert(command.end(), {"--question", "--switch", "--extra-button=Cancel", + "--extra-button=No", "--extra-button=Yes"}); + break; + case choice::retry_cancel: + command.insert(command.end(), + {"--question", "--switch", "--extra-button=Cancel", "--extra-button=Retry"}); + break; + case choice::abort_retry_ignore: + command.insert(command.end(), {"--question", "--switch", "--extra-button=Ignore", + "--extra-button=Abort", "--extra-button=Retry"}); + break; + case choice::ok: + default: + switch (_icon) { + case icon::error: + command.push_back("--error"); + break; + case icon::warning: + command.push_back("--warning"); + break; + default: + command.push_back("--info"); + break; + } + } + + command.insert(command.end(), + {"--title", title, "--width=300", "--height=0", // sensible defaults + "--no-markup", // do not interpret text as Pango markup + "--text", text, "--icon-name=dialog-" + get_icon_name(_icon)}); + } else if (is_kdialog()) { + if (_choice == choice::ok) { + switch (_icon) { + case icon::error: + command.push_back("--error"); + break; + case icon::warning: + command.push_back("--sorry"); + break; + default: + command.push_back("--msgbox"); + break; + } + } else { + std::string flag = "--"; + if (_icon == icon::warning || _icon == icon::error) flag += "warning"; + flag += "yesno"; + if (_choice == choice::yes_no_cancel) flag += "cancel"; + command.push_back(flag); + if (_choice == choice::yes_no || _choice == choice::yes_no_cancel) { + m_mappings[0] = button::yes; + m_mappings[256] = button::no; + } + } + + command.push_back(text); + command.push_back("--title"); + command.push_back(title); + + // Must be after the above part + if (_choice == choice::ok_cancel) + command.insert(command.end(), {"--yes-label", "OK", "--no-label", "Cancel"}); + } + + if (flags(flag::is_verbose)) std::cerr << "pfd: " << command << std::endl; + + m_async->start_process(command); #endif - } - - inline button message::result() - { - int exit_code; - auto ret = m_async->result(&exit_code); - // osascript will say "button returned:Cancel\n" - // and others will just say "Cancel\n" - if (internal::ends_with(ret, "Cancel\n")) - return button::cancel; - if (internal::ends_with(ret, "OK\n")) - return button::ok; - if (internal::ends_with(ret, "Yes\n")) - return button::yes; - if (internal::ends_with(ret, "No\n")) - return button::no; - if (internal::ends_with(ret, "Abort\n")) - return button::abort; - if (internal::ends_with(ret, "Retry\n")) - return button::retry; - if (internal::ends_with(ret, "Ignore\n")) - return button::ignore; - if (m_mappings.count(exit_code) != 0) - return m_mappings[exit_code]; - return exit_code == 0 ? button::ok : button::cancel; - } - - // open_file implementation - - inline open_file::open_file(std::string const& title, - std::string const& default_path /* = "" */, - std::vector<std::string> const& filters /* = { "All Files", "*" } */, - opt options /* = opt::none */) - : file_dialog(type::open, title, default_path, filters, options) - { - } - - inline open_file::open_file(std::string const& title, - std::string const& default_path, - std::vector<std::string> const& filters, - bool allow_multiselect) - : open_file(title, default_path, filters, (allow_multiselect ? opt::multiselect : opt::none)) - { - } - - inline std::vector<std::string> open_file::result() - { - return vector_result(); - } - - // save_file implementation - - inline save_file::save_file(std::string const& title, - std::string const& default_path /* = "" */, - std::vector<std::string> const& filters /* = { "All Files", "*" } */, - opt options /* = opt::none */) - : file_dialog(type::save, title, default_path, filters, options) - { - } - - inline save_file::save_file(std::string const& title, - std::string const& default_path, - std::vector<std::string> const& filters, - bool confirm_overwrite) - : save_file(title, default_path, filters, (confirm_overwrite ? opt::none : opt::force_overwrite)) - { - } - - inline std::string save_file::result() - { - return string_result(); - } - - // select_folder implementation - - inline select_folder::select_folder(std::string const& title, - std::string const& default_path /* = "" */, - opt options /* = opt::none */) - : file_dialog(type::folder, title, default_path, {}, options) - { - } - - inline std::string select_folder::result() - { - return string_result(); - } - -#endif // PFD_SKIP_IMPLEMENTATION - -} // namespace pfd
\ No newline at end of file +} + +inline button message::result() { + int exit_code; + auto ret = m_async->result(&exit_code); + // osascript will say "button returned:Cancel\n" + // and others will just say "Cancel\n" + if (internal::ends_with(ret, "Cancel\n")) return button::cancel; + if (internal::ends_with(ret, "OK\n")) return button::ok; + if (internal::ends_with(ret, "Yes\n")) return button::yes; + if (internal::ends_with(ret, "No\n")) return button::no; + if (internal::ends_with(ret, "Abort\n")) return button::abort; + if (internal::ends_with(ret, "Retry\n")) return button::retry; + if (internal::ends_with(ret, "Ignore\n")) return button::ignore; + if (m_mappings.count(exit_code) != 0) return m_mappings[exit_code]; + return exit_code == 0 ? button::ok : button::cancel; +} + +// open_file implementation + +inline open_file::open_file(std::string const& title, std::string const& default_path /* = "" */, + std::vector<std::string> const& filters /* = { "All Files", "*" } */, + opt options /* = opt::none */) + : file_dialog(type::open, title, default_path, filters, options) {} + +inline open_file::open_file(std::string const& title, std::string const& default_path, + std::vector<std::string> const& filters, bool allow_multiselect) + : open_file(title, default_path, filters, (allow_multiselect ? opt::multiselect : opt::none)) {} + +inline std::vector<std::string> open_file::result() { + return vector_result(); +} + +// save_file implementation + +inline save_file::save_file(std::string const& title, std::string const& default_path /* = "" */, + std::vector<std::string> const& filters /* = { "All Files", "*" } */, + opt options /* = opt::none */) + : file_dialog(type::save, title, default_path, filters, options) {} + +inline save_file::save_file(std::string const& title, std::string const& default_path, + std::vector<std::string> const& filters, bool confirm_overwrite) + : save_file(title, default_path, filters, + (confirm_overwrite ? opt::none : opt::force_overwrite)) {} + +inline std::string save_file::result() { + return string_result(); +} + +// select_folder implementation + +inline select_folder::select_folder(std::string const& title, + std::string const& default_path /* = "" */, + opt options /* = opt::none */) + : file_dialog(type::folder, title, default_path, {}, options) {} + +inline std::string select_folder::result() { + return string_result(); +} + +#endif // PFD_SKIP_IMPLEMENTATION + +} // namespace pfd
\ No newline at end of file diff --git a/public/tools/ld.dyn/src/CommandLine.cc b/public/tools/ld.dyn/src/CommandLine.cc index 90a79796..377f22fa 100644 --- a/public/tools/ld.dyn/src/CommandLine.cc +++ b/public/tools/ld.dyn/src/CommandLine.cc @@ -8,40 +8,34 @@ /// @brief Library loader. -#define DYNLIB_FLAG "-dyn" - -SInt32 _NeMain(SInt32 argc, Char* argv[]) -{ - SCI_UNUSED(argc); - SCI_UNUSED(argv); - - PrintOut(nullptr, "%s", "ld.dyn: Dynamic Loader.\n"); - PrintOut(nullptr, "%s", "ld.dyn: © 2024-2025 Amlal El Mahrouss, All rights reserved.\n"); - - for (SInt32 i = 1U; i < argc; ++i) - { - if (MmStrCmp(argv[i], DYNLIB_FLAG) == 0) - { - UIntPtr ret = RtlSpawnProcess(argv[i], 0, nullptr, nullptr, 0); - - if (0 < ret) - { - return RtlSpawnIB(ret); - } - - PrintOut(nullptr, "%s", "ld.dyn: Failed to load the library.\n"); - PrintOut(nullptr, "%s", "ld.dyn: Make sure the library is valid.\n"); - - break; - } - else - { - PrintOut(nullptr, "%s", "ld.dyn: Invalid argument.\n"); - PrintOut(nullptr, "%s", "ld.dyn: Use -dyn <path> to load a dynamic library.\n"); - - break; - } - } - - return EXIT_FAILURE; +#define DYNLIB_FLAG "-dyn" + +SInt32 _NeMain(SInt32 argc, Char* argv[]) { + SCI_UNUSED(argc); + SCI_UNUSED(argv); + + PrintOut(nullptr, "%s", "ld.dyn: Dynamic Loader.\n"); + PrintOut(nullptr, "%s", "ld.dyn: © 2024-2025 Amlal El Mahrouss, All rights reserved.\n"); + + for (SInt32 i = 1U; i < argc; ++i) { + if (MmStrCmp(argv[i], DYNLIB_FLAG) == 0) { + UIntPtr ret = RtlSpawnProcess(argv[i], 0, nullptr, nullptr, 0); + + if (0 < ret) { + return RtlSpawnIB(ret); + } + + PrintOut(nullptr, "%s", "ld.dyn: Failed to load the library.\n"); + PrintOut(nullptr, "%s", "ld.dyn: Make sure the library is valid.\n"); + + break; + } else { + PrintOut(nullptr, "%s", "ld.dyn: Invalid argument.\n"); + PrintOut(nullptr, "%s", "ld.dyn: Use -dyn <path> to load a dynamic library.\n"); + + break; + } + } + + return EXIT_FAILURE; } diff --git a/public/tools/ld.fwrk/src/CommandLine.cc b/public/tools/ld.fwrk/src/CommandLine.cc index cdb57133..0fbaaf2e 100644 --- a/public/tools/ld.fwrk/src/CommandLine.cc +++ b/public/tools/ld.fwrk/src/CommandLine.cc @@ -8,13 +8,12 @@ /// @brief This program loads a code framework into Kernel's memory. -SInt32 _NeMain(SInt32 argc, Char* argv[]) -{ - SCI_UNUSED(argc); - SCI_UNUSED(argv); +SInt32 _NeMain(SInt32 argc, Char* argv[]) { + SCI_UNUSED(argc); + SCI_UNUSED(argv); - PrintOut(nullptr, "%s", "ld.fwrk: Framework Loader.\n"); - PrintOut(nullptr, "%s", "ld.fwrk: © 2024-2025 Amlal El Mahrouss, All rights reserved.\n"); + PrintOut(nullptr, "%s", "ld.fwrk: Framework Loader.\n"); + PrintOut(nullptr, "%s", "ld.fwrk: © 2024-2025 Amlal El Mahrouss, All rights reserved.\n"); - return EXIT_FAILURE; + return EXIT_FAILURE; } diff --git a/public/tools/mk.fwrk/Common.h b/public/tools/mk.fwrk/Common.h index 09e374ee..be016be6 100644 --- a/public/tools/mk.fwrk/Common.h +++ b/public/tools/mk.fwrk/Common.h @@ -1,12 +1,12 @@ /** - Sat Oct 26 07:03:28 AM CEST 2024 - (c) Amlal El Mahrouss. + Sat Oct 26 07:03:28 AM CEST 2024 + (c) Amlal El Mahrouss. */ #ifndef APPS_COMMON_H #define APPS_COMMON_H -#include <user/SystemCalls.h> #include <CoreFoundation.fwrk/headers/Foundation.h> +#include <user/SystemCalls.h> -#endif // APPS_COMMON_H +#endif // APPS_COMMON_H diff --git a/public/tools/mk.fwrk/Framework.h b/public/tools/mk.fwrk/Framework.h index ab03d0bc..9beb6da4 100644 --- a/public/tools/mk.fwrk/Framework.h +++ b/public/tools/mk.fwrk/Framework.h @@ -1,6 +1,6 @@ /** - Thu Oct 17 07:57:43 CEST 2024 - (c) Amlal El Mahrouss. + Thu Oct 17 07:57:43 CEST 2024 + (c) Amlal El Mahrouss. */ #ifndef APPS_FRAMEWORK_H @@ -11,7 +11,7 @@ #define kExecDirectory "bin/" #define kRsrcDirectory "xml/" #define kRootDirectory "/" -#define kFKExtension ".fwrk" -#define kAppExtension ".app" +#define kFKExtension ".fwrk" +#define kAppExtension ".app" -#endif // !APPS_FRAMEWORK_H +#endif // !APPS_FRAMEWORK_H diff --git a/public/tools/mk.fwrk/Steps.h b/public/tools/mk.fwrk/Steps.h index 51927def..3017b92e 100644 --- a/public/tools/mk.fwrk/Steps.h +++ b/public/tools/mk.fwrk/Steps.h @@ -1,6 +1,6 @@ /** - Thu Oct 17 07:57:43 CEST 2024 - (c) Amlal El Mahrouss. + Thu Oct 17 07:57:43 CEST 2024 + (c) Amlal El Mahrouss. */ #ifndef APPS_STEPS_H @@ -10,23 +10,22 @@ #include <Framework.h> #define kStepsExtension ".stp" -#define kStepsStrLen (256U) +#define kStepsStrLen (256U) -#define kStepsMagic " pls" +#define kStepsMagic " pls" #define kStepsMagicLen (4U) -#define kStepsVersion (0x0100) +#define kStepsVersion (0x0100) #define kStepsMime "ne-application-kind/steps" -struct STEPS_COMMON_RECORD final -{ - Char magic[kStepsMagicLen]; - Char name[kStepsStrLen]; - Char company[kStepsStrLen]; - Char author[kStepsStrLen]; - SInt32 version; - SInt32 pages; - SInt32 check_page, eula_page; +struct STEPS_COMMON_RECORD final { + Char magic[kStepsMagicLen]; + Char name[kStepsStrLen]; + Char company[kStepsStrLen]; + Char author[kStepsStrLen]; + SInt32 version; + SInt32 pages; + SInt32 check_page, eula_page; }; -#endif // ifndef APPS_STEPS_H
\ No newline at end of file +#endif // ifndef APPS_STEPS_H
\ No newline at end of file diff --git a/public/tools/mk.fwrk/src/CommandLine.cc b/public/tools/mk.fwrk/src/CommandLine.cc index 8f142dfb..202f21bb 100644 --- a/public/tools/mk.fwrk/src/CommandLine.cc +++ b/public/tools/mk.fwrk/src/CommandLine.cc @@ -13,107 +13,97 @@ /// @brief This program makes a framework/app/steps directory for NeKernel OS. -static const Char* kStepsName = "Steps"; +static const Char* kStepsName = "Steps"; static const Char* kStepsAuthor = "John Doe"; static const Char* kStepsCompany = "Company, Inc"; -SInt32 _NeMain(SInt32 argc, Char* argv[]) -{ - CF::CFArray<const char*, 256U> files; +SInt32 _NeMain(SInt32 argc, Char* argv[]) { + CF::CFArray<const char*, 256U> files; - auto ext = kFKExtension; + auto ext = kFKExtension; - for (SInt32 i = 2UL; i < argc; ++i) - { - if (MmStrCmp(argv[i], "-h") == 0) - { - PrintOut(nullptr, "%s", "make_app: Framework/Application Creation Tool.\n"); - PrintOut(nullptr, "%s", "make_app: © 2024-2025 Amlal El Mahrouss, All rights reserved.\n"); + for (SInt32 i = 2UL; i < argc; ++i) { + if (MmStrCmp(argv[i], "-h") == 0) { + PrintOut(nullptr, "%s", "make_app: Framework/Application Creation Tool.\n"); + PrintOut(nullptr, "%s", "make_app: © 2024-2025 Amlal El Mahrouss, All rights reserved.\n"); - PrintOut(nullptr, "%s", "make_app: -a: Application Directory.\n"); - PrintOut(nullptr, "%s", "make_app: -s: Steps (Setup pages) Directory.\n"); - PrintOut(nullptr, "%s", "make_app: -f: Framework Directory.\n"); + PrintOut(nullptr, "%s", "make_app: -a: Application Directory.\n"); + PrintOut(nullptr, "%s", "make_app: -s: Steps (Setup pages) Directory.\n"); + PrintOut(nullptr, "%s", "make_app: -f: Framework Directory.\n"); - return kErrorSuccess; - } + return kErrorSuccess; + } - if (MmStrCmp(argv[i], "--author") == 0) - { - MmCopyMemory(const_cast<Char*>(kStepsAuthor), const_cast<Char*>(argv[i + 1]), MmStrLen(argv[i + 1])); - continue; - } + if (MmStrCmp(argv[i], "--author") == 0) { + MmCopyMemory(const_cast<Char*>(kStepsAuthor), const_cast<Char*>(argv[i + 1]), + MmStrLen(argv[i + 1])); + continue; + } - if (MmStrCmp(argv[i], "--company") == 0) - { - MmCopyMemory(const_cast<Char*>(kStepsCompany), const_cast<Char*>(argv[i + 1]), MmStrLen(argv[i + 1])); - continue; - } + if (MmStrCmp(argv[i], "--company") == 0) { + MmCopyMemory(const_cast<Char*>(kStepsCompany), const_cast<Char*>(argv[i + 1]), + MmStrLen(argv[i + 1])); + continue; + } - if (MmStrCmp(argv[i], "--name") == 0) - { - MmCopyMemory(const_cast<Char*>(kStepsName), const_cast<Char*>(argv[i + 1]), MmStrLen(argv[i + 1])); - continue; - } + if (MmStrCmp(argv[i], "--name") == 0) { + MmCopyMemory(const_cast<Char*>(kStepsName), const_cast<Char*>(argv[i + 1]), + MmStrLen(argv[i + 1])); + continue; + } - if (MmStrCmp(argv[i], "-a") == 0) - { - ext = kAppExtension; - continue; - } - else if (MmStrCmp(argv[i], "-s") == 0) - { - ext = kStepsExtension; - continue; - } - else if (MmStrCmp(argv[i], "-f") == 0) - { - ext = kFKExtension; - continue; - } + if (MmStrCmp(argv[i], "-a") == 0) { + ext = kAppExtension; + continue; + } else if (MmStrCmp(argv[i], "-s") == 0) { + ext = kStepsExtension; + continue; + } else if (MmStrCmp(argv[i], "-f") == 0) { + ext = kFKExtension; + continue; + } - files[i] = argv[i]; - } + files[i] = argv[i]; + } - auto path = argv[1]; + auto path = argv[1]; - if (FsCreateDir(path)) - { - FsCreateDir(StrFmt("{}{}", path, kRootDirectory)); - FsCreateDir(StrFmt("{}{}", path, kExecDirectory)); + if (FsCreateDir(path)) { + FsCreateDir(StrFmt("{}{}", path, kRootDirectory)); + FsCreateDir(StrFmt("{}{}", path, kExecDirectory)); - if (MmStrCmp(ext, kStepsExtension) == 0) - { - FsCreateFile(StrFmt("{}{}{}{}", path, kRootDirectory, "_setup")); + if (MmStrCmp(ext, kStepsExtension) == 0) { + FsCreateFile(StrFmt("{}{}{}{}", path, kRootDirectory, "_setup")); - auto handle = IoOpenFile(StrFmt("{}{}{}{}", path, kRootDirectory, "_setup", kStepsExtension), nullptr); + auto handle = + IoOpenFile(StrFmt("{}{}{}{}", path, kRootDirectory, "_setup", kStepsExtension), nullptr); - struct STEPS_COMMON_RECORD record; + struct STEPS_COMMON_RECORD record; - MmFillMemory(&record, sizeof(STEPS_COMMON_RECORD), 0); + MmFillMemory(&record, sizeof(STEPS_COMMON_RECORD), 0); - MmCopyMemory(record.name, const_cast<Char*>(kStepsName), kStepsStrLen); - MmCopyMemory(record.author, const_cast<Char*>(kStepsAuthor), kStepsStrLen); - MmCopyMemory(record.company, const_cast<Char*>(kStepsCompany), kStepsStrLen); + MmCopyMemory(record.name, const_cast<Char*>(kStepsName), kStepsStrLen); + MmCopyMemory(record.author, const_cast<Char*>(kStepsAuthor), kStepsStrLen); + MmCopyMemory(record.company, const_cast<Char*>(kStepsCompany), kStepsStrLen); - MmCopyMemory(record.magic, const_cast<Char*>(kStepsMagic), kStepsMagicLen); + MmCopyMemory(record.magic, const_cast<Char*>(kStepsMagic), kStepsMagicLen); - record.version = kStepsVersion; + record.version = kStepsVersion; - IoWriteFile(handle, (void*)&record, sizeof(STEPS_COMMON_RECORD)); - IoCloseFile(handle); + IoWriteFile(handle, (void*) &record, sizeof(STEPS_COMMON_RECORD)); + IoCloseFile(handle); - handle = nullptr; - } + handle = nullptr; + } - for (auto i = 0UL; i < files.Count(); ++i) - { - auto& file = files[i]; + for (auto i = 0UL; i < files.Count(); ++i) { + auto& file = files[i]; - FsCopy(path, StrFmt("{}{}", path, file)); - } + FsCopy(path, StrFmt("{}{}", path, file)); + } - return kErrorSuccess; - } + return kErrorSuccess; + } - return kErrorInternal; + return kErrorInternal; } diff --git a/public/tools/mk.hefs/src/CommandLine.cc b/public/tools/mk.hefs/src/CommandLine.cc index 0c30e1b1..dd8be97f 100644 --- a/public/tools/mk.hefs/src/CommandLine.cc +++ b/public/tools/mk.hefs/src/CommandLine.cc @@ -8,10 +8,9 @@ /// @brief Placeholder program. -SInt32 _NeMain(SInt32 argc, Char* argv[]) -{ - SCI_UNUSED(argc); - SCI_UNUSED(argv); +SInt32 _NeMain(SInt32 argc, Char* argv[]) { + SCI_UNUSED(argc); + SCI_UNUSED(argv); - return EXIT_FAILURE; + return EXIT_FAILURE; } diff --git a/public/tools/mk.nefs/src/CommandLine.cc b/public/tools/mk.nefs/src/CommandLine.cc index 0c30e1b1..dd8be97f 100644 --- a/public/tools/mk.nefs/src/CommandLine.cc +++ b/public/tools/mk.nefs/src/CommandLine.cc @@ -8,10 +8,9 @@ /// @brief Placeholder program. -SInt32 _NeMain(SInt32 argc, Char* argv[]) -{ - SCI_UNUSED(argc); - SCI_UNUSED(argv); +SInt32 _NeMain(SInt32 argc, Char* argv[]) { + SCI_UNUSED(argc); + SCI_UNUSED(argv); - return EXIT_FAILURE; + return EXIT_FAILURE; } diff --git a/public/tools/open/src/CommandLine.cc b/public/tools/open/src/CommandLine.cc index b3779c71..f2378599 100644 --- a/public/tools/open/src/CommandLine.cc +++ b/public/tools/open/src/CommandLine.cc @@ -9,41 +9,39 @@ /// @brief This program opens an application from **OPEN_APP_BASE_PATH** /// @file CommandLine.cc -#define OPEN_APP_APP_FLAG "-a" +#define OPEN_APP_APP_FLAG "-a" #define OPEN_APP_HELP_FLAG "-h" #define OPEN_APP_BASE_PATH "/app/" -SInt32 _NeMain(SInt32 argc, Char* argv[]) -{ - if (argc == 1) - return EXIT_FAILURE; +SInt32 _NeMain(SInt32 argc, Char* argv[]) { + if (argc == 1) return EXIT_FAILURE; - PrintOut(nullptr, "open: Open Loader.\n"); - PrintOut(nullptr, "open: © 2024-2025 Amlal El Mahrouss, All rights reserved.\n"); + PrintOut(nullptr, "open: Open Loader.\n"); + PrintOut(nullptr, "open: © 2024-2025 Amlal El Mahrouss, All rights reserved.\n"); - for (SInt32 i = 1U; i < argc; ++i) - { - if (MmStrCmp(argv[i], OPEN_APP_HELP_FLAG) == 0) - { - PrintOut(nullptr, "open: %s: Application is being taken as the input (opens a PEF/PE32+ program depending on the CPU architecture).\n", OPEN_APP_APP_FLAG); + for (SInt32 i = 1U; i < argc; ++i) { + if (MmStrCmp(argv[i], OPEN_APP_HELP_FLAG) == 0) { + PrintOut(nullptr, + "open: %s: Application is being taken as the input (opens a PEF/PE32+ program " + "depending on the CPU architecture).\n", + OPEN_APP_APP_FLAG); - return EXIT_SUCCESS; - } - else if (MmStrCmp(argv[i], OPEN_APP_APP_FLAG) == 0) - { - if ((i + 1) == argc) - return EXIT_FAILURE; - else if ((i + 2) == argc) - return EXIT_FAILURE; + return EXIT_SUCCESS; + } else if (MmStrCmp(argv[i], OPEN_APP_APP_FLAG) == 0) { + if ((i + 1) == argc) + return EXIT_FAILURE; + else if ((i + 2) == argc) + return EXIT_FAILURE; - Char base_path[FILE_MAX_LEN] = OPEN_APP_BASE_PATH; - MmCopyMemory(base_path + MmStrLen(OPEN_APP_BASE_PATH), argv[i + 1], MmStrLen(argv[i + 1])); + Char base_path[FILE_MAX_LEN] = OPEN_APP_BASE_PATH; + MmCopyMemory(base_path + MmStrLen(OPEN_APP_BASE_PATH), argv[i + 1], MmStrLen(argv[i + 1])); - UIntPtr ret = RtlSpawnProcess(StrFmt("{}/dist/{]}", base_path, argv[i + 2]), 0, nullptr, nullptr, 0); + UIntPtr ret = + RtlSpawnProcess(StrFmt("{}/dist/{]}", base_path, argv[i + 2]), 0, nullptr, nullptr, 0); - return ret; - } - } + return ret; + } + } - return EXIT_FAILURE; + return EXIT_FAILURE; } |
