Start work on phonebook tool.
This commit is contained in:
parent
cc17abea53
commit
a6d7b948d4
97
Arena.cc
97
Arena.cc
|
@ -12,9 +12,11 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#define PROT_RW (PROT_WRITE|PROT_READ)
|
||||
#elif defined(__WIN64__) || defined(__WIN32__)
|
||||
#elif defined(__WIN64__) || defined(__WIN32__) || defined(WIN32)
|
||||
#include <Windows.h>
|
||||
#include <winbase.h>
|
||||
#include <fileapi.h>
|
||||
#include <strsafe.h>
|
||||
#endif
|
||||
|
||||
#include <ios>
|
||||
|
@ -27,7 +29,8 @@ namespace klib {
|
|||
|
||||
Arena::Arena()
|
||||
: store(nullptr), size(0), fd(0), arenaType(ArenaType::Uninit)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Arena::~Arena()
|
||||
|
@ -141,17 +144,52 @@ Arena::Create(const char *path, size_t fileSize, mode_t mode)
|
|||
|
||||
return this->Open(path);
|
||||
}
|
||||
#elif defined(__WIN64__) || defined(__WIN32__)
|
||||
#elif defined(__WIN64__) || defined(__WIN32__) || defined(WIN32)
|
||||
static void
|
||||
displayWinErr(LPTSTR lpszFunction)
|
||||
{
|
||||
// Retrieve the system error message for the last-error code
|
||||
|
||||
LPVOID lpMsgBuf;
|
||||
LPVOID lpDisplayBuf;
|
||||
DWORD dw = GetLastError();
|
||||
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
dw,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0, NULL );
|
||||
|
||||
// Display the error message and exit the process
|
||||
|
||||
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
|
||||
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
|
||||
StringCchPrintf((LPTSTR)lpDisplayBuf,
|
||||
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
|
||||
TEXT("%s failed with error %d: %s"),
|
||||
lpszFunction, dw, lpMsgBuf);
|
||||
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
|
||||
|
||||
LocalFree(lpMsgBuf);
|
||||
LocalFree(lpDisplayBuf);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Arena::Open(const char *path)
|
||||
{
|
||||
HANDLE fHandle;
|
||||
size_t fSize;
|
||||
size_t fRead = 0;
|
||||
size_t fRemaining;
|
||||
auto cursor = this->store;
|
||||
OVERLAPPED overlap;
|
||||
HANDLE fHandle;
|
||||
DWORD fRead = 0;
|
||||
size_t fSize;
|
||||
size_t fRemaining;
|
||||
auto *cursor = this->store;
|
||||
OVERLAPPED overlap;
|
||||
|
||||
std::cout << "CreateFileA\n";
|
||||
fHandle = CreateFileA(
|
||||
(LPSTR)path,
|
||||
GENERIC_READ,
|
||||
|
@ -161,10 +199,13 @@ Arena::Open(const char *path)
|
|||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
if (fHandle == INVALID_HANDLE_VALUE) {
|
||||
displayWinErr("CreateFileA");
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cout << "GetFileSizeEx\n";
|
||||
if (!GetFileSizeEx(fHandle, reinterpret_cast<PLARGE_INTEGER>(&fSize))) {
|
||||
displayWinErr("GetFileSizeEx");
|
||||
CloseHandle(fHandle);
|
||||
return -1;
|
||||
}
|
||||
|
@ -173,8 +214,12 @@ Arena::Open(const char *path)
|
|||
|
||||
fRemaining = fSize;
|
||||
while (fRemaining != 0) {
|
||||
std::cout << "ReadFile\n";
|
||||
overlap.Offset = (fSize - fRemaining);
|
||||
if (!ReadFile(fHandle, cursor, fSize, reinterpret_cast<LPDWORD>(&fRead), &overlap)) {
|
||||
if (ReadFile(fHandle, cursor, fSize,
|
||||
&fRead,
|
||||
&overlap) != TRUE) {
|
||||
displayWinErr("ReadFile");
|
||||
CloseHandle(fHandle);
|
||||
this->Destroy();
|
||||
return -1;
|
||||
|
@ -187,9 +232,39 @@ Arena::Open(const char *path)
|
|||
CloseHandle(fHandle);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
Arena::Create(const char *path, size_t fileSize, DWORD mode)
|
||||
{
|
||||
HANDLE fHandle;
|
||||
|
||||
std::cout << "Create::CreateFileA\n";
|
||||
fHandle = CreateFileA(
|
||||
(LPSTR)path,
|
||||
GENERIC_READ|GENERIC_WRITE,
|
||||
mode,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
if (fHandle == INVALID_HANDLE_VALUE) {
|
||||
displayWinErr("Create::CreateFileA");
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cout << "SetFileValidData\n";
|
||||
if (SetFileValidData(fHandle, fileSize) != fileSize) {
|
||||
displayWinErr("SetFileValidData");
|
||||
CloseHandle(fHandle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
CloseHandle(fHandle);
|
||||
return this->Open(path);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
Arena::CursorInArena(const uint8_t *cursor)
|
||||
{
|
||||
|
|
55
Arena.h
55
Arena.h
|
@ -22,14 +22,34 @@
|
|||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "Exceptions.h"
|
||||
|
||||
|
||||
#if defined(__WIN64__) || defined(__WIN32__) || defined(WIN32)
|
||||
|
||||
#include <Windows.h>
|
||||
#include <fileapi.h>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
namespace klib {
|
||||
|
||||
/// DefaultFileMode is a sane set of default permissions that can be used for a
|
||||
/// new Arena.
|
||||
#if defined(__linux__)
|
||||
static constexpr mode_t DefaultFileMode = 0644;
|
||||
#elif defined(__WIN64__) || defined(__WIN32__) || defined(WIN32)
|
||||
static constexpr DWORD DefaultFileMode =
|
||||
(FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE);
|
||||
#endif
|
||||
|
||||
|
||||
/// \enum ArenaType
|
||||
///
|
||||
/// ArenaType describes the type of \class Arena.
|
||||
enum class ArenaType : uint8_t {
|
||||
enum class ArenaType
|
||||
: uint8_t {
|
||||
/// Uninit is an unintialized arena.
|
||||
Uninit,
|
||||
/// Static is an arena backed by a static block of memory.
|
||||
|
@ -83,7 +103,7 @@ public:
|
|||
/// \return Returns 0 on success and -1 on error.
|
||||
int SetAlloc(size_t allocSize);
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
/// MemoryMap points the arena to a memory-mapped file. This is
|
||||
/// currently only supported on Linux. If the arena is already backed,
|
||||
/// then #Destroy will be called first.
|
||||
|
@ -91,8 +111,14 @@ public:
|
|||
/// \param memFileDes File descriptor to map into memory.
|
||||
/// \param memSize The size of memory to map.
|
||||
/// \return Returns 0 on success and -1 on error.
|
||||
int MemoryMap(int memFileDes, size_t memSize); // Arena will own fd.
|
||||
#if defined(__linux__)
|
||||
int MemoryMap(int memFileDes, size_t memSize);
|
||||
#else
|
||||
|
||||
int MemoryMap(int memFileDes, size_t memSize)
|
||||
{ throw NotImplemented("WIN32"); }
|
||||
|
||||
#endif
|
||||
/// Create creates a new file, truncating it if it already exists. On
|
||||
/// Unix-based platforms, the arena will be backed by a memory via
|
||||
/// #MemoryMap. On other platforms (e.g. Windows), the arena will read
|
||||
|
@ -102,8 +128,13 @@ public:
|
|||
/// \param fileSize The size of the file to create.
|
||||
/// \param mode The permissions to load.
|
||||
/// \return Returns 0 on success and -1 on error.
|
||||
#if defined(__linux__)
|
||||
int Create(const char *path, size_t fileSize, mode_t mode);
|
||||
#elif defined(__WIN64__) || defined(__WIN32__) || defined(WIN32)
|
||||
|
||||
int Create(const char *path, size_t fileSize, DWORD mode);
|
||||
|
||||
#endif
|
||||
/// Open reads a file into the arena; the file must already exist. On
|
||||
/// Unix-based platforms, the arena will be backed by a memory via
|
||||
/// #MemoryMap. On other platforms (e.g. Windows), the arena will read
|
||||
|
@ -113,27 +144,30 @@ public:
|
|||
///
|
||||
/// \param path The path to the file to be loaded.
|
||||
/// \return Returns 0 on success and -1 on error.
|
||||
#if defined(__linux__)
|
||||
int Open(const char *path);
|
||||
#elif defined(__WIN64__) || defined(__WIN32__)
|
||||
int Open(const char *path);
|
||||
#elif defined(__WIN64__) || defined(__WIN32__) || defined(WIN32)
|
||||
int Open(const char *path);
|
||||
#endif
|
||||
|
||||
/// NewCursor returns a pointer to the start of the memory in the arena.
|
||||
///
|
||||
/// \return A pointer to the start of the arena memory.
|
||||
uint8_t *NewCursor() const { return this->store; }
|
||||
uint8_t *NewCursor() const
|
||||
{ return this->store; }
|
||||
|
||||
/// End returns a pointer to the end of the arena memory.
|
||||
///
|
||||
/// \return A pointer to the end of the arena memory.
|
||||
uint8_t *End() { return this->store + this->size; }
|
||||
uint8_t *End()
|
||||
{ return this->store + this->size; }
|
||||
|
||||
/// CursorInArena checks whether the cursor is still in the arena.
|
||||
///
|
||||
/// \param cursor A pointer that ostensibly points to the arena's
|
||||
/// memory.
|
||||
/// \return True if the cursor is still in the arena.
|
||||
bool CursorInArena(const uint8_t *cursor);
|
||||
bool CursorInArena(const uint8_t *cursor);
|
||||
|
||||
/// Returns the current size of the arena.
|
||||
///
|
||||
|
@ -148,7 +182,8 @@ public:
|
|||
{ return this->arenaType; }
|
||||
|
||||
/// Ready returns whether the arena is initialized.
|
||||
bool Ready() const { return this->Type() != ArenaType::Uninit; };
|
||||
bool Ready() const
|
||||
{ return this->Type() != ArenaType::Uninit; };
|
||||
|
||||
/// Clear zeroizes the memory in the arena.
|
||||
void Clear();
|
||||
|
@ -198,7 +233,7 @@ private:
|
|||
/// \param os
|
||||
/// \param arena
|
||||
/// \return
|
||||
std::ostream &operator<<(std::ostream& os, Arena &arena);
|
||||
std::ostream &operator<<(std::ostream &os, Arena &arena);
|
||||
|
||||
|
||||
} // namespace klib
|
||||
|
|
|
@ -24,6 +24,7 @@ set(HEADER_FILES
|
|||
Arena.h
|
||||
Buffer.h
|
||||
Dictionary.h
|
||||
Exceptions.h
|
||||
Test.h
|
||||
TLV.h)
|
||||
|
||||
|
@ -31,14 +32,13 @@ set(SOURCE_FILES
|
|||
Arena.cc
|
||||
Buffer.cc
|
||||
Dictionary.cc
|
||||
Exceptions.cpp
|
||||
Test.cc
|
||||
TLV.cc)
|
||||
|
||||
add_library(klib STATIC
|
||||
Arena.cc
|
||||
Buffer.cc
|
||||
Dictionary.cc
|
||||
TLV.cc)
|
||||
add_library(klib STATIC ${SOURCE_FILES} ${HEADER_FILES})
|
||||
add_executable(phonebook phonebook.cpp)
|
||||
target_link_libraries(phonebook klib)
|
||||
|
||||
include(CTest)
|
||||
enable_testing()
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// Created by kyle on 2023-10-10.
|
||||
//
|
||||
|
||||
#include "Exceptions.h"
|
||||
|
||||
|
||||
namespace klib {
|
||||
|
||||
|
||||
AssertionFailed::AssertionFailed(std::string message) : msg(message)
|
||||
{
|
||||
}
|
||||
|
||||
char *
|
||||
AssertionFailed::what()
|
||||
{
|
||||
return const_cast<char *>(this->msg.c_str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// Created by kyle on 2023-10-10.
|
||||
//
|
||||
|
||||
#ifndef KLIB_EXCEPTIONS_H
|
||||
#define KLIB_EXCEPTIONS_H
|
||||
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
namespace klib {
|
||||
|
||||
|
||||
class NotImplemented : public std::exception {
|
||||
public:
|
||||
explicit NotImplemented(const char *pl) : platform((char *)pl) {}
|
||||
char *what() {
|
||||
return this->platform;
|
||||
}
|
||||
private:
|
||||
char *platform;
|
||||
};
|
||||
|
||||
|
||||
/// AssertionFailed indicates that some invariant didn't hold.
|
||||
class AssertionFailed : public std::exception {
|
||||
public:
|
||||
/// AssertionFailed is constructed with a message describing what
|
||||
/// failed.
|
||||
explicit AssertionFailed(std::string message);
|
||||
|
||||
/// what returns a message describing the exception.
|
||||
char *what();
|
||||
|
||||
private:
|
||||
std::string msg;
|
||||
};
|
||||
|
||||
|
||||
} // namespace klib
|
||||
|
||||
|
||||
#endif //KLIB_EXCEPTIONS_H
|
12
Test.cc
12
Test.cc
|
@ -2,6 +2,7 @@
|
|||
// Created by kyle on 2023-10-09.
|
||||
//
|
||||
|
||||
#include "Exceptions.h"
|
||||
#include "Test.h"
|
||||
|
||||
|
||||
|
@ -28,15 +29,4 @@ TestAssert(bool condition, std::string message = "Assertion failed.")
|
|||
}
|
||||
|
||||
|
||||
AssertionFailed::AssertionFailed(std::string message) : msg(message)
|
||||
{
|
||||
}
|
||||
|
||||
char *
|
||||
AssertionFailed::what()
|
||||
{
|
||||
return const_cast<char *>(this->msg.c_str());
|
||||
}
|
||||
|
||||
|
||||
} // namespace klib
|
||||
|
|
15
Test.h
15
Test.h
|
@ -27,21 +27,6 @@ namespace klib {
|
|||
inline void TestAssert(bool condition, std::string message);
|
||||
|
||||
|
||||
/// AssertionFailed indicates that some invariant didn't hold.
|
||||
class AssertionFailed : public std::exception {
|
||||
public:
|
||||
/// AssertionFailed is constructed with a message describing what
|
||||
/// failed.
|
||||
explicit AssertionFailed(std::string message);
|
||||
|
||||
/// what returns a message describing the exception.
|
||||
char *what();
|
||||
|
||||
private:
|
||||
std::string msg;
|
||||
};
|
||||
|
||||
|
||||
} // namespace klib
|
||||
|
||||
#endif //KLIB_TEST_H
|
||||
|
|
8
klib.h
8
klib.h
|
@ -25,6 +25,14 @@
|
|||
#define KLIB_KLIB_H
|
||||
|
||||
|
||||
#include <klib/Arena.h>
|
||||
#include <klib/Buffer.h>
|
||||
#include <klib/Dictionary.h>
|
||||
#include <klib/Exceptions.h>
|
||||
#include <klib/TLV.h>
|
||||
#include <klib/Test.h>
|
||||
|
||||
|
||||
/// klib is the top-level namespace containing all the code in this library.
|
||||
namespace klib {
|
||||
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
//
|
||||
// Created by kyle on 2023-10-10.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
using namespace std;
|
||||
|
||||
#include "Arena.h"
|
||||
#include "Dictionary.h"
|
||||
using namespace klib;
|
||||
|
||||
static const char *defaultPhonebook = "pb.dat";
|
||||
|
||||
static void
|
||||
usage(ostream &os, int exc)
|
||||
{
|
||||
os << "phonebook is a tool for interacting with phonebook files.\n";
|
||||
os << "\nThe default filename is pb.dat.\n\n";
|
||||
os << "Usage:\n";
|
||||
os << "\tphonebook [-f file] list\n";
|
||||
os << "\tphonebook [-f file] del key\n";
|
||||
os << "\tphonebook [-f file] has key\n";
|
||||
os << "\tphonebook [-f file] get key value\n";
|
||||
os << "\tphonebook [-f file] put key value\n";
|
||||
os << "\n";
|
||||
|
||||
exit(exc);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
Arena arena;
|
||||
Dictionary pb(arena);
|
||||
char *pbFile = (char *)defaultPhonebook;
|
||||
int optind = 1;
|
||||
|
||||
for (optind; optind < argc; optind++) {
|
||||
auto arg = string(argv[optind]);
|
||||
if (arg[0] != '-') break;
|
||||
if (arg == "-h") usage(cout, 0);
|
||||
if (arg == "-f") {
|
||||
pbFile = argv[optind+1];
|
||||
optind++;
|
||||
continue;
|
||||
}
|
||||
|
||||
usage(cerr, 1);
|
||||
}
|
||||
|
||||
if (argc <= 1) {
|
||||
usage(cout, 0);
|
||||
}
|
||||
|
||||
cout << "[+] loading phonebook from " << pbFile << "\n";
|
||||
if (arena.Open(pbFile) != 0) {
|
||||
cerr << "Failed to open " << pbFile << "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
auto command = string(argv[optind++]);
|
||||
|
||||
if (command == "list") {
|
||||
cout << pb << "\n";
|
||||
} else if (command == "del") {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -97,7 +97,6 @@ main(int argc, const char *argv[])
|
|||
}
|
||||
arenaStatic.Clear();
|
||||
|
||||
#if defined(__linux__)
|
||||
Arena arenaFile;
|
||||
|
||||
if (-1 == arenaFile.Create(ARENA_FILE, ARENA_SIZE, 0644)) {
|
||||
|
@ -105,7 +104,6 @@ main(int argc, const char *argv[])
|
|||
} else if (!runSuite(arenaFile, "arenaFile")) {
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (-1 == arenaMem.SetAlloc(ARENA_SIZE)) {
|
||||
abort();
|
||||
|
|
Loading…
Reference in New Issue