Skip to content

Commit

Permalink
Portability Generalise for Windows.
Browse files Browse the repository at this point in the history
  • Loading branch information
NotCompsky committed Sep 19, 2020
1 parent 1b61b36 commit d3badd2
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 47 deletions.
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ if(NATIVE_MARCH)
endif()


if(WIN32)
set(ENABLE_STATIC ON)
endif()


set(LIBS)
if(ENABLE_STATIC)
set(PNG_NAMES png.a libpng.a)
Expand Down
14 changes: 13 additions & 1 deletion src/errors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@


enum {
NO_ERROR,
NAH_NO_ERROR,
MISC_ERROR,

TOO_MUCH_DATA_TO_ENCODE,
Expand Down Expand Up @@ -45,6 +45,12 @@ enum {
UNLIKELY_LONG_FILE_NAME,
CANNOT_CREATE_FILE,

CANNOT_READ_FROM_STDIN,
CANNOT_WRITE_TO_STDOUT,
MISMATCH_BETWEEN_BYTES_READ_AND_WRITTEN,

COULD_NOT_GET_FILE_SIZE,

N_ERRORS
};

Expand Down Expand Up @@ -95,6 +101,12 @@ const char* const handler_msgs[] = {
"Improbably long file name",
"Cannot create file",

"Cannot read from stdin",
"Cannot write to stdout",
"Mismatch between bytes read and written",

"Could not get file size",

""
};
#endif
Expand Down
2 changes: 1 addition & 1 deletion src/fmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ int main(const int argc, char** argv){
if (unlikely(n_msg_bytes == 0))
handler(TRYING_TO_ENCODE_MSG_OF_0_BYTES);
os::write_exact_number_of_bytes_to_stdout((char*)(&n_msg_bytes), 8);
os::sendfile_from_stdout_to_file(fp, n_msg_bytes);
os::sendfile_from_file_to_stdout(fp, n_msg_bytes);
}
// After all messages, signal end with signalled size of 0
constexpr char zero[32] = {0};
Expand Down
127 changes: 115 additions & 12 deletions src/fmt_os.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,20 @@
#endif


#ifdef _WIN32
static const char path_sep = '\\';
constexpr HANDLE INVALID_HANDLE_VALUE2 = INVALID_HANDLE_VALUE;
#else
static const char path_sep = '/';
constexpr int INVALID_HANDLE_VALUE = -1;
constexpr int INVALID_HANDLE_VALUE2 = 0;
#endif


char* get_parent_dir(char* path){
do {
--path;
} while ((*path != '/'));
} while ((*path != path_sep));
// No need to check whether path has overflown the full file path beginning, because we can assume the root path begins with a slash - and we would not encounter root anyway.
return path;
}
Expand All @@ -23,38 +33,75 @@ char* get_parent_dir(char* path){
char* get_child_dir(char* path, char* const end_of_full_file_path){
do {
++path;
} while ((*path != '/') and (path != end_of_full_file_path));
return (*path == '/') ? path : nullptr;
} while ((*path != path_sep) and (path != end_of_full_file_path));
return (*path == path_sep) ? path : nullptr;
}


bool mkdir_path_between_pointers(char* const start, char* const end){
*end = 0;
#ifdef _WIN32
const bool rc = CreateDirectoryA(start, nullptr); // TODO: Set security attributes
// Return code doesn't distinguish between ERROR_ALREADY_EXISTS and ERROR_PATH_NOT_FOUND
#else
const int rc = mkdir(start, S_IRUSR | S_IWUSR | S_IXUSR);
if (rc == -1){
if (unlikely(errno != ENOENT))
handler(CANNOT_CREATE_FILE, start);
}
*end = '/';
#endif
*end = path_sep;
return (rc == 0); // i.e. return true on a success
}


fout_typ create_file(const char* const file_path){
#ifdef _WIN32
return CreateFileA(file_path, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
#else
return open(file_path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IXUSR);
#endif
}


fout_typ open_file_for_reading(const char* const file_path){
#ifdef _WIN32
return CreateFileA(file_path, GENERIC_READ, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
#else
return open(file_path, O_RDONLY);
#endif
}


void close_file_handle(const fout_typ fd){
#ifdef _WIN32
CloseHandle(fd);
#else
close(fd);
#endif
}


namespace os {


int create_file_with_parent_dirs(char* const file_path, const size_t file_path_len){
fout_typ create_file_with_parent_dirs(char* const file_path, const size_t file_path_len){
#ifdef CHITTY_CHATTY
fprintf(stderr, "Creating file: %s\n", file_path);
#endif

int fd = open(file_path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IXUSR);
if (likely(fd != -1))
fout_typ fd = create_file(file_path);

if (likely(fd != INVALID_HANDLE_VALUE))
// File successfully created
return fd;
#ifdef _WIN32
// No information in documentation about possible error codes of GetLastError(), so we'll just assume that the error was due to a parent directory not existing
#else
if (unlikely(errno != ENOENT)){
handler(CANNOT_CREATE_FILE, file_path);
}
#endif

// ENOENT: Either a directory component in pathname does not exist or is a dangling symbolic link

Expand All @@ -74,37 +121,83 @@ int create_file_with_parent_dirs(char* const file_path, const size_t file_path_
mkdir_path_between_pointers(file_path, path);
}

return open(file_path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IXUSR);
return create_file(path);
}


void read_exact_number_of_bytes_from_stdin(char* const buf, const size_t n){
size_t offset = 0;
do {
#ifdef _WIN32
DWORD n_bytes_read;
if (unlikely(ReadFile(GetStdHandle(STD_INPUT_HANDLE), buf + offset, n - offset, &n_bytes_read, nullptr) == 0))
handler(CANNOT_READ_FROM_STDIN);
offset += n_bytes_read;
#else
offset += read(STDIN_FILENO, buf + offset, n - offset);
#endif
} while (offset != n);
}


void write_exact_number_of_bytes_to_stdout(char* const buf, size_t n){
do {
#ifdef _WIN32
DWORD n_bytes_read;
if (unlikely(WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, n, &n_bytes_read, nullptr) == 0))
handler(CANNOT_WRITE_TO_STDOUT);
n -= n_bytes_read;
#else
n -= write(STDOUT_FILENO, buf, n);
#endif
} while (n != 0);
}


void sendfile_from_stdout_to_file(const char* const fp, const size_t n_bytes){
const int msg_file = open(fp, O_RDONLY);
if (unlikely(msg_file == 0))
#ifdef _WIN32
void win__transfer_data_between_files(HANDLE in, HANDLE out, size_t n_bytes){
do {
static char buf[1024 * 64];

size_t n_bytes_to_transfer = sizeof(buf);
if (n_bytes_to_transfer > n_bytes)
n_bytes_to_transfer = n_bytes;

DWORD n_bytes_read;
if (unlikely(ReadFile(in, buf, n_bytes_to_transfer, &n_bytes_read, nullptr) == 0))
handler(CANNOT_READ_FROM_STDIN);
DWORD n_bytes_written;
if (unlikely(WriteFile(out, buf, n_bytes_to_transfer, &n_bytes_written, nullptr) == 0))
handler(CANNOT_WRITE_TO_STDOUT);

if (unlikely((n_bytes_read != n_bytes_to_transfer) or (n_bytes_written != n_bytes_to_transfer)))
handler(MISMATCH_BETWEEN_BYTES_READ_AND_WRITTEN);

n_bytes -= n_bytes_to_transfer;
} while (n_bytes != 0);
}
#endif


void sendfile_from_file_to_stdout(const char* const fp, const size_t n_bytes){
const fout_typ msg_file = open_file_for_reading(fp);
if (unlikely(msg_file == INVALID_HANDLE_VALUE2))
handler(CANNOT_OPEN_FILE);
#ifdef _WIN32
win__transfer_data_between_files(msg_file, GetStdHandle(STD_OUTPUT_HANDLE), n_bytes);
#else
const auto rc5 = sendfile(STDOUT_FILENO, msg_file, nullptr, n_bytes);
if (unlikely(rc5 == -1))
handler(SENDFILE_ERROR);
close(msg_file);
#endif
close_file_handle(msg_file);
}


void splice_from_stdin_to_fd(const fout_typ fout, const size_t n_bytes){
#ifdef _WIN32
win__transfer_data_between_files(GetStdHandle(STD_INPUT_HANDLE), fout, n_bytes);
#else
loff_t n_bytes_written = 0;
size_t n_bytes_yet_to_write = n_bytes;
do {
Expand All @@ -129,16 +222,26 @@ void splice_from_stdin_to_fd(const fout_typ fout, const size_t n_bytes){
}
n_bytes_yet_to_write -= n_writ;
} while(n_bytes_yet_to_write != 0);
#endif
}


#ifdef EMBEDDOR
size_t get_file_sz(const char* const fp){
#ifdef _WIN32
HANDLE const f = open_file_for_reading(fp);
_LARGE_INTEGER f_sz; // For x86_32 compatibility
if (unlikely(GetFileSizeEx(f, &f_sz) == 0))
handler(COULD_NOT_GET_FILE_SIZE);
close_file_handle(f);
return f_sz.QuadPart;
#else
static struct stat stat_buf;
const auto rc3 = stat(fp, &stat_buf);
if (unlikely(rc3 == -1))
handler(COULD_NOT_STAT_FILE, fp);
return stat_buf.st_size;
#endif
}
#endif

Expand Down
5 changes: 3 additions & 2 deletions src/fmt_os.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@


#ifdef _WIN32
# include <windows.h>
typedef HANDLE fout_typ;
# define STDOUT_DESCR GetStdHandle(STD_OUTPUT_HANDLE);
#else
Expand All @@ -20,11 +21,11 @@ void read_exact_number_of_bytes_from_stdin(char* const buf, const size_t n);

void write_exact_number_of_bytes_to_stdout(char* const buf, size_t n);

void sendfile_from_stdout_to_file(const char* const fp, const size_t n_bytes);
void sendfile_from_file_to_stdout(const char* const fp, const size_t n_bytes);

void splice_from_stdin_to_fd(const fout_typ fout, const size_t n_bytes);

int create_file_with_parent_dirs(char* const file_path, const size_t file_path_len);
fout_typ create_file_with_parent_dirs(char* const file_path, const size_t file_path_len);

size_t get_file_sz(const char* const fp);

Expand Down
34 changes: 34 additions & 0 deletions src/os.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,40 @@
#include "os.hpp"


#define WHILE_CONDITION while(not bpcs_stream.exhausted)
#ifdef ONLY_COUNT
# define DO_OR_WHILE WHILE_CONDITION
# define WHILE_OR_DO
#else
# define DO_OR_WHILE do
# define WHILE_OR_DO WHILE_CONDITION;
#endif


#ifdef _WIN32
template<size_t sz>
bool write_to_stdout(uchar(&io_buf)[sz]){
LPDWORD n_bytes_read_ptr;
if (unlikely(WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), io_buf, sz, n_bytes_read_ptr, nullptr) != 0))
return true;
return (*n_bytes_read_ptr == sz);
}
# define WRITE_STMT write_to_stdout(io_buf)
template<size_t sz>
bool read_from_stdin(uchar(&io_buf)[sz]){
LPDWORD n_bytes_read_ptr;
if (unlikely(ReadFile(GetStdHandle(STD_INPUT_HANDLE), io_buf, BYTES_PER_GRID, n_bytes_read_ptr, nullptr) != 0))
return true;
return (*n_bytes_read_ptr == BYTES_PER_GRID);
}
# define READ_STMT read_from_stdin(io_buf)
#else
# include <unistd.h>
# define WRITE_STMT write(STDOUT_FILENO, io_buf, sizeof(io_buf)) != sizeof(io_buf)
# define READ_STMT read (STDIN_FILENO, io_buf, BYTES_PER_GRID) == BYTES_PER_GRID
#endif


namespace os {


Expand Down
32 changes: 1 addition & 31 deletions src/os.hpp
Original file line number Diff line number Diff line change
@@ -1,38 +1,8 @@
#pragma once

#include "bpcs.hpp"


#define WHILE_CONDITION while(not bpcs_stream.exhausted)
#ifdef ONLY_COUNT
# define DO_OR_WHILE WHILE_CONDITION
# define WHILE_OR_DO
#else
# define DO_OR_WHILE do
# define WHILE_OR_DO WHILE_CONDITION;
#endif

#ifdef _WIN32
inline
bool write_to_stdout(){
long n_bytes_read;
if (unlikely(WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), io_buf, sizeof(io_buf), &n_bytes_read, nullptr) != 0))
return true;
return (n_bytes_read == sizeof(io_buf));
}
# define WRITE_STMT write_to_stdout()
inline
bool read_from_stdin(){
long n_bytes_read;
if (unlikely(ReadFile(GetStdHandle(STD_INPUT_HANDLE), io_buf, BYTES_PER_GRID, &n_bytes_read, nullptr) != 0))
return true;
return (n_bytes_read == BYTES_PER_GRID);
}
# define READ_STMT read_from_stdin()
#else
# include <unistd.h>
# define WRITE_STMT write(STDOUT_FILENO, io_buf, sizeof(io_buf)) != sizeof(io_buf)
# define READ_STMT read (STDIN_FILENO, io_buf, BYTES_PER_GRID) == BYTES_PER_GRID
# include "windows.h"
#endif


Expand Down

0 comments on commit d3badd2

Please sign in to comment.