Skip to content

Commit 6cf521d

Browse files
authored
Merge pull request #35 from deadem/pr34
Pr34
2 parents 49586fd + 2f81e34 commit 6cf521d

17 files changed

+468
-422
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ ipch
66
.vs/
77
*.aps
88
linter.vcxproj.user
9+
enc_temp_folder/

FilePipe.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include "stdafx.h"
2+
#include "FilePipe.h"
3+
4+
#include "SystemError.h"
5+
6+
Linter::FilePipe::Pipe Linter::FilePipe::create()
7+
{
8+
SECURITY_ATTRIBUTES security;
9+
10+
security.nLength = sizeof(SECURITY_ATTRIBUTES);
11+
security.bInheritHandle = TRUE;
12+
security.lpSecurityDescriptor = nullptr;
13+
14+
HANDLE parent;
15+
HANDLE child;
16+
if (!CreatePipe(&parent, &child, &security, 0))
17+
{
18+
throw SystemError(GetLastError());
19+
}
20+
21+
return {HandleWrapper(parent), HandleWrapper(child)};
22+
}
23+
24+
void Linter::FilePipe::detachFromParent(const HandleWrapper &handle)
25+
{
26+
if (!SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0))
27+
{
28+
throw SystemError(GetLastError());
29+
}
30+
}

FilePipe.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#pragma once
2+
3+
#include "HandleWrapper.h"
4+
5+
namespace Linter
6+
{
7+
class FilePipe
8+
{
9+
public:
10+
struct Pipe
11+
{
12+
HandleWrapper m_reader;
13+
HandleWrapper m_writer;
14+
};
15+
16+
static Pipe create();
17+
static void detachFromParent(const HandleWrapper &handle);
18+
};
19+
} // namespace Linter

HandleWrapper.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#include "stdafx.h"
2+
#include "HandleWrapper.h"
3+
4+
#include "SystemError.h"
5+
6+
using namespace Linter;
7+
8+
HandleWrapper::HandleWrapper(HANDLE h) : m_handle(h)
9+
{
10+
if (h == INVALID_HANDLE_VALUE)
11+
{
12+
throw SystemError();
13+
}
14+
}
15+
16+
HandleWrapper::HandleWrapper(HandleWrapper &&other) noexcept : m_handle(std::exchange(other.m_handle, INVALID_HANDLE_VALUE))
17+
{
18+
}
19+
20+
void HandleWrapper::close() const
21+
{
22+
if (m_handle != INVALID_HANDLE_VALUE)
23+
{
24+
HANDLE h{std::exchange(m_handle, INVALID_HANDLE_VALUE)};
25+
CloseHandle(h);
26+
}
27+
}
28+
29+
HandleWrapper::operator HANDLE() const noexcept
30+
{
31+
return m_handle;
32+
}
33+
34+
HandleWrapper::~HandleWrapper()
35+
{
36+
close();
37+
}
38+
39+
void HandleWrapper::writeFile(std::string const &str) const
40+
{
41+
static_assert(sizeof(str[0]) == 1, "Invalid byte size");
42+
43+
char const *start = str.c_str();
44+
char const *end = start + str.size();
45+
while (start != end)
46+
{
47+
const auto toWrite = static_cast<DWORD>(end - start);
48+
DWORD written;
49+
if (!WriteFile(m_handle, start, toWrite, &written, nullptr))
50+
{
51+
const DWORD err = GetLastError();
52+
throw SystemError(err);
53+
}
54+
start += written;
55+
}
56+
}
57+
58+
std::string HandleWrapper::readFile() const
59+
{
60+
std::string result;
61+
62+
std::string buffer;
63+
buffer.resize(0x4000);
64+
65+
for (;;)
66+
{
67+
DWORD readBytes;
68+
//The API suggests when the other end closes the pipe, you should get 0. What appears to happen
69+
//is that you get broken pipe.
70+
if (!ReadFile(m_handle, &buffer[0], static_cast<DWORD>(buffer.size()), &readBytes, nullptr))
71+
{
72+
DWORD err = GetLastError();
73+
if (err != ERROR_BROKEN_PIPE)
74+
{
75+
throw SystemError(err);
76+
}
77+
}
78+
79+
if (readBytes == 0)
80+
{
81+
break;
82+
}
83+
84+
result += std::string(&buffer[0], readBytes);
85+
}
86+
87+
return result;
88+
}

HandleWrapper.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#pragma once
2+
3+
#include <string>
4+
5+
namespace Linter
6+
{
7+
class HandleWrapper
8+
{
9+
public:
10+
explicit HandleWrapper(HANDLE h);
11+
HandleWrapper(HandleWrapper const &) = delete;
12+
HandleWrapper(HandleWrapper &&other) noexcept;
13+
HandleWrapper &operator=(HandleWrapper const &) = delete;
14+
HandleWrapper &operator=(HandleWrapper &&other) = delete;
15+
~HandleWrapper();
16+
17+
void close() const;
18+
19+
operator HANDLE() const noexcept;
20+
21+
/** Write a string to the handle
22+
*
23+
* @param str - string to write
24+
*/
25+
void writeFile(std::string const &str) const;
26+
27+
/** Read the entire file */
28+
std::string readFile() const;
29+
30+
private:
31+
mutable HANDLE m_handle;
32+
};
33+
} // namespace Linter

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ Optional attribute `stdin`="1" can be used to lint from stdin instead of temp fi
2828
<linter stdin="1" extension=".js" command="C:\Users\deadem\AppData\Roaming\npm\eslint.cmd --stdin --format checkstyle"/>
2929
```
3030

31+
To handle spaces in names, you should use the &quot; quote character, as follows:
32+
33+
```xml
34+
<linter extension=".none" command="&quot;C:\a command with spaces\thing&quot; --stuff" />
35+
```
36+
3137
Optional parameter
3238

3339
You can change default colors by an optional "style" tag. "color" attribute is a RGB hex color value, "alpha" value can range from 0 (completely transparent) to 255 (no transparency).

SourceLocation.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#pragma once
2+
#include <string>
3+
4+
#if __cplusplus >= 202002L
5+
#include <source_location>
6+
#endif
7+
8+
namespace Linter
9+
{
10+
#if __cplusplus >= 202002L
11+
using SourceLocation = std::source_location;
12+
#else
13+
struct SourceLocation
14+
{
15+
struct Location
16+
{
17+
unsigned int line() const noexcept
18+
{
19+
return 0;
20+
}
21+
const char *file_name() const noexcept
22+
{
23+
return "";
24+
}
25+
const char *function_name() const noexcept
26+
{
27+
return "";
28+
}
29+
};
30+
static Location current()
31+
{
32+
return {};
33+
}
34+
};
35+
#endif
36+
37+
using SourceLocationCurrent = decltype(SourceLocation::current());
38+
} // namespace Linter

SystemError.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#include "StdAfx.h"
2+
3+
#include "SystemError.h"
4+
5+
#include "encoding.h"
6+
7+
#include <cstdio>
8+
#include <system_error>
9+
10+
#include <comdef.h>
11+
#include <winbase.h>
12+
13+
using namespace Linter;
14+
15+
SystemError::SystemError(const SourceLocationCurrent &location) : SystemError(GetLastError(), location)
16+
{
17+
}
18+
19+
SystemError::SystemError(std::string const &info, const SourceLocationCurrent &location) : SystemError(GetLastError(), info, location)
20+
{
21+
}
22+
23+
SystemError::SystemError(DWORD err, const SourceLocationCurrent &location)
24+
{
25+
// Note: Technically, the message function could fail.
26+
std::snprintf(m_buff, sizeof(m_buff), "%s", std::system_category().message(err).c_str());
27+
addLocationToMessage(location);
28+
}
29+
30+
SystemError::SystemError(DWORD err, std::string const &info, const SourceLocationCurrent &location)
31+
{
32+
// Note: Technically, the message function could fail.
33+
std::snprintf(m_buff, sizeof(m_buff), "%s - %s", info.c_str(), std::system_category().message(err).c_str());
34+
addLocationToMessage(location);
35+
}
36+
37+
SystemError::SystemError(HRESULT err, const SourceLocationCurrent &location)
38+
{
39+
IErrorInfo *err_info{nullptr};
40+
(void)GetErrorInfo(0, &err_info);
41+
_com_error error{err, err_info};
42+
std::snprintf(m_buff, sizeof(m_buff), "%s", Encoding::toUTF(std::wstring(error.ErrorMessage())).c_str());
43+
addLocationToMessage(location);
44+
}
45+
46+
SystemError::SystemError(HRESULT err, std::string const &info, const SourceLocationCurrent &location)
47+
{
48+
IErrorInfo *err_info{nullptr};
49+
(void)GetErrorInfo(0, &err_info);
50+
_com_error error{err, err_info};
51+
std::snprintf(m_buff, sizeof(m_buff), "%s - %s", info.c_str(), Encoding::toUTF(std::wstring(error.ErrorMessage())).c_str());
52+
addLocationToMessage(location);
53+
}
54+
55+
SystemError::~SystemError() = default;
56+
57+
char const *Linter::SystemError::what() const noexcept
58+
{
59+
return &m_buff[0];
60+
}
61+
62+
void SystemError::addLocationToMessage(const SourceLocationCurrent &location)
63+
{
64+
const char *fullPath = location.file_name();
65+
if (fullPath == nullptr || fullPath[0] == 0)
66+
{
67+
return;
68+
}
69+
70+
const char *fileName = std::strrchr(fullPath, '\\');
71+
const std::size_t used{std::strlen(m_buff)};
72+
std::snprintf(m_buff + used,
73+
sizeof(m_buff) - used,
74+
" at %s:%d %s",
75+
(fileName ? fileName + 1 : fullPath),
76+
location.line(),
77+
location.function_name());
78+
}

SystemError.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#pragma once
2+
#include "SourceLocation.h"
3+
4+
#include <exception>
5+
#include <string>
6+
7+
namespace Linter
8+
{
9+
class SystemError : public std::exception
10+
{
11+
12+
public:
13+
/** Creates an exception object from the current system error */
14+
explicit SystemError(const SourceLocationCurrent &location = SourceLocation::current());
15+
16+
/** Creates an exception object from the current system error, appends string */
17+
explicit SystemError(std::string const &, const SourceLocationCurrent &location = SourceLocation::current());
18+
19+
/** Creates an exception object given a system error number */
20+
explicit SystemError(DWORD err, const SourceLocationCurrent &location = SourceLocation::current());
21+
22+
/** Creates an exception object from specified error with addition information string */
23+
SystemError(DWORD err, std::string const &, const SourceLocationCurrent &location = SourceLocation::current());
24+
25+
/** Creates an exception object given an HRESULT */
26+
explicit SystemError(HRESULT err, const SourceLocationCurrent &location = SourceLocation::current());
27+
28+
/** Creates an exception object from specified error with addition information string */
29+
SystemError(HRESULT err, std::string const &, const SourceLocationCurrent &location = SourceLocation::current());
30+
31+
~SystemError();
32+
33+
char const *what() const noexcept override;
34+
35+
private:
36+
char m_buff[2048];
37+
38+
void addLocationToMessage(const SourceLocationCurrent &location);
39+
};
40+
} // namespace Linter

0 commit comments

Comments
 (0)