Skip to content

Commit

Permalink
TileCTL initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Nicholas O'Connor committed Mar 24, 2016
1 parent 5a2c11f commit cbeba86
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 32 deletions.
92 changes: 60 additions & 32 deletions Tilandis/Tilandis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,36 +29,9 @@ int CALLBACK wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR, int nShow) {
}
if (Tilandis::UsingCommandLine(argc, argv)) { // FIXME: Commandline processing, while it works, is extremely friggin weird because I wrote it stoned
try {
if (Tilandis::DeleteMode && Tilandis::CreateMode) { throw Tilandis::Exceptions::BadArgCombo; }
if (Tilandis::DeleteMode) { Tilandis::Links::DeleteLink(); }
if (Tilandis::CreateMode) {
try {
bool success = Tilandis::Links::CreateLink();
if (!success) {
std::wcout << Tilandis::Err << std::endl;
}
}
catch (Tilandis::Exceptions::BadCommandLine exc) {
wchar_t* excwhat = L"";
const char* excwhatmbs = "";
excwhatmbs = exc.what(); // we do it this way because the (reasonably) paranoid compiler doesn't reckon the pointer will always be initialized
mbstowcs_s(NULL, excwhat, strlen(excwhatmbs) + 1, excwhatmbs, (size_t) 2048);
MessageBox(NULL, excwhat, L"Tilandis", 0);
return 1;
}
}
if (Tilandis::AddToRegistry) {
bool result = Tilandis::RegisterProtocol();
if (!result) {
MessageBox(NULL, L"Failed to register Tilandis with specified protocol (hint: this function needs administrator rights)", L"Tilandis", MB_ICONERROR);
return 1;
}
else {
MessageBox(NULL, L"Tilandis has \"successfully\" registered itself with the specified protocol.\r\nBe aware that though no error is reported, many failure cases aren't currently detected. If it still doesn't work, you'll have to double-check the registry yourself.\n\n(Note: If you have TileCreator Proxy installed, you may have to change the associations in the Default Programs control panel.)",
L"Tilandis", 0);
return 0;
}
}
bool result = Tilandis::ManipulateLinkDocument();
if (result) { return 0; }
else { return 1; }
}
catch (Tilandis::Exceptions::BadCommandLine exc) {
std::wcout << exc.what() << std::endl;
Expand All @@ -67,12 +40,36 @@ int CALLBACK wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR, int nShow) {
}
else {
if (argc == 1) {
Tilandis::PrintUsage(argv[0]); // TODO: make this run a GUI instead
Tilandis::PrintUsage(argv[0]);
}
else if (argc == 2) {
std::wstring LinkName = argv[1];
size_t pos;
if ((pos = LinkName.find(L":")) != std::wstring::npos) { // if we FIND a colon
if (LinkName.substr(0, pos) == L"tilectl") {
switch (Tilandis::ParseTileCTL(LinkName)) {
case True:
try {
bool result = Tilandis::ManipulateLinkDocument();
if (result) { return 0; }
else { return 2; }
} catch (Tilandis::Exceptions::BadCommandLine exc) {
std::wcout << exc.what() << std::endl;
return 2;
}
case Mixed: // returns Mixed on "successful, but..."
try {
bool result = Tilandis::ManipulateLinkDocument();
if (result) { return 1; } else { return 2; }
} catch (Tilandis::Exceptions::BadCommandLine exc) {
std::wcout << exc.what() << std::endl;
return 2;
}
return 1;
case False:
return 2;
}
}
LinkName.erase(0, pos + 1); // Remove protocols from the beginning
wchar_t nasties[] = L"/\\\r\n";
for (size_t i = 0; i < wcslen(nasties); ++i) { // slash removal
Expand Down Expand Up @@ -136,4 +133,35 @@ bool Tilandis::RegisterProtocol() {
result = RegSetValueEx(subregistry, NULL, 0, REG_SZ, (LPBYTE) regbytes, 65535);
if (result != ERROR_SUCCESS) { return false; }
return true;
}
}

bool Tilandis::ManipulateLinkDocument() {
if (Tilandis::DeleteMode && Tilandis::CreateMode) { throw Tilandis::Exceptions::BadArgCombo; }
if (Tilandis::DeleteMode) { Tilandis::Links::DeleteLink(); }
if (Tilandis::CreateMode) {
try {
bool success = Tilandis::Links::CreateLink();
if (!success) {
std::wcout << Tilandis::Err << std::endl;
}
} catch (Tilandis::Exceptions::BadCommandLine exc) {
wchar_t* excwhat = L"";
const char* excwhatmbs = "";
excwhatmbs = exc.what(); // we do it this way because the (reasonably) paranoid compiler doesn't reckon the pointer will always be initialized
mbstowcs_s(NULL, excwhat, strlen(excwhatmbs) + 1, excwhatmbs, (size_t) 2048);
MessageBox(NULL, excwhat, L"Tilandis", 0);
return false;
}
}
if (Tilandis::AddToRegistry) {
bool result = Tilandis::RegisterProtocol();
if (!result) {
MessageBox(NULL, L"Failed to register Tilandis with specified protocol (hint: this function needs administrator rights)", L"Tilandis", MB_ICONERROR);
return 1;
} else {
MessageBox(NULL, L"Tilandis has \"successfully\" registered itself with the specified protocol.\r\nBe aware that though no error is reported, many failure cases aren't currently detected. If it still doesn't work, you'll have to double-check the registry yourself.\n\n(Note: If you have TileCreator Proxy installed, you may have to change the associations in the Default Programs control panel.)",
L"Tilandis", 0);
return true;
}
}
}
3 changes: 3 additions & 0 deletions Tilandis/Tilandis.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "rapidjson\document.h"
#include "resource.h"
#include "tristate.h"
#include "tilectl.h"

// Home namespace
namespace Tilandis {
Expand Down Expand Up @@ -68,6 +69,8 @@ namespace Tilandis {
}

extern bool RegisterProtocol();

extern bool ManipulateLinkDocument();
}

extern std::wstring basedir(std::wstring);
Expand Down
79 changes: 79 additions & 0 deletions Tilandis/tilectl.cpp
Original file line number Diff line number Diff line change
@@ -1,2 +1,81 @@
#include "Tilandis.h"
#include "exceptions.h"

tristate Tilandis::ParseTileCTL(std::wstring ctlcmd) {
ctlcmd.erase(0, 10); // erases "tilectl://"

// TileCTL cliff notes:
// tilectl://<command>/<link>?option=value&option=value
// examples without tilectl:// prefix:
// new/notepad?path=C:\Windows\notepad.exe&workdir=C:\Windows&args=C:\file.txt&admin=true
// delete/notepad
// "edit" and "launch" might happen, currently uncertain

// This particular implementation moves through each part of the tilectl command by erasing the parts
// it's already understood. This is not required by any standard, it just happens to be the easiest
// thing for me to implement at the moment (plus I think it helps with memory management?)

// command
size_t slashpos = ctlcmd.find(L'/');
std::wstring command = ctlcmd.substr(0, slashpos);
ctlcmd.erase(0, slashpos + 1);

// link name (and args, if we have them)
bool hasargs;
size_t questpos = ctlcmd.find(L'?');

if (questpos != ctlcmd.npos) { // ? is present
hasargs = true;
Tilandis::LinkName = ctlcmd.substr(0, questpos);
ctlcmd.erase(0, questpos + 1);

// Count the args so we know how long the for loop is going to be
// this enables the erase method so I don't have to think about the math
size_t andpos = 0;
int numargs = 1; // The below while loop will never run if there's only one argument
// and we wouldn't have gotten this far if there were 0
while ((andpos = ctlcmd.find(L'&', andpos)) != ctlcmd.npos) { // for each & in the remaining ctlcmd
numargs++;
}

for (int i = 0; i < numargs; i++) {
andpos = ctlcmd.find(L'&');
std::wstring curarg = ctlcmd.substr(0, andpos);

size_t equalspos = curarg.find(L'=');
std::wstring option = curarg.substr(0, equalspos);
std::wstring value = curarg.substr(equalspos + 1, curarg.npos);

if (option == L"path") { Tilandis::PathName = value; }
else if (option == L"args") { Tilandis::Args = value; }
else if (option == L"workdir") { Tilandis::WorkingDirectory = value; }
else if (option == L"admin") {
std::transform(value.begin(), value.end(), value.begin(), ::towlower); // lowercase string

if (value == L"true") { Tilandis::LinkInAdminMode = true; }
}

ctlcmd.erase(0, andpos + 1);
}
} else {
hasargs = false;
Tilandis::LinkName = ctlcmd;
ctlcmd.erase(0, ctlcmd.npos); // should empty the string
}

std::transform(command.begin(), command.end(), command.begin(), ::towlower); // lowercase string
if (command == L"new") {
if (!hasargs) {
throw Tilandis::Exceptions::MissingArg;
return False;
} else if (Tilandis::LinkName == L"") {
throw Tilandis::Exceptions::MissingArg;
return False;
} else if (Tilandis::PathName == L"") {
throw Tilandis::Exceptions::MissingArg;
return False;
}

Tilandis::CreateMode = true;
}
}
9 changes: 9 additions & 0 deletions Tilandis/tilectl.h
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
#pragma once
#ifndef __TILECTL_H
#define __TILECTL_H
#include "Tilandis.h"

namespace Tilandis {
extern tristate ParseTileCTL(std::wstring ctlcmd);
}

#endif // !__TILECTL_H

0 comments on commit cbeba86

Please sign in to comment.