Win32: unbreak solvespace-cli.

It was broken because of three bugs:
  * Uninitialized variables in RunCommand;
  * Trying to use (OEM-encoded) main() argc/argv arguments instead
    of GetCommandLineW();
  * Trying to pass relative paths directly into ssfopen.
pull/135/head
whitequark 2016-12-05 00:25:31 +00:00
parent 679a1f0ded
commit 4a0b4fd8d3
10 changed files with 116 additions and 87 deletions

View File

@ -41,14 +41,14 @@ static bool RunBenchmark(std::function<void()> setupFn,
}
int main(int argc, char **argv) {
InitPlatform();
std::vector<std::string> args = InitPlatform(argc, argv);
std::string mode, filename;
if(argc == 3) {
mode = argv[1];
filename = argv[2];
if(args.size() == 3) {
mode = args[1];
filename = args[2];
} else {
fprintf(stderr, "Usage: %s [mode] [filename]\n", argv[0]);
fprintf(stderr, "Usage: %s [mode] [filename]\n", args[0].c_str());
fprintf(stderr, "Mode can be one of: load.\n");
return 1;
}

View File

@ -81,7 +81,7 @@ void Slvs_MakeQuaternion(double ux, double uy, double uz,
void Slvs_Solve(Slvs_System *ssys, Slvs_hGroup shg)
{
if(!IsInit) {
InitPlatform();
InitPlatform(0, NULL);
IsInit = 1;
}

View File

@ -10,8 +10,8 @@ namespace SolveSpace {
extern std::shared_ptr<Pixmap> framebuffer;
}
static void ShowUsage(const char *argv0) {
fprintf(stderr, "Usage: %s <command> <options> <filename> [filename...]", argv0);
static void ShowUsage(const std::string &argv0) {
fprintf(stderr, "Usage: %s <command> <options> <filename> [filename...]", argv0.c_str());
//-----------------------------------------------------------------------------> 80 col */
fprintf(stderr, R"(
When run, performs an action specified by <command> on every <filename>.
@ -81,14 +81,14 @@ static void ShowUsage(const char *argv0) {
FormatListFromFileFilter(SurfaceFileFilter).c_str());
}
static bool RunCommand(size_t argc, char **argv) {
if(argc < 2) return false;
static bool RunCommand(const std::vector<std::string> args) {
if(args.size() < 2) return false;
std::function<void(const std::string &)> runner;
std::vector<std::string> inputFiles;
auto ParseInputFile = [&](size_t &argn) {
std::string arg = argv[argn];
std::string arg = args[argn];
if(arg[0] != '-') {
inputFiles.push_back(arg);
return true;
@ -97,42 +97,42 @@ static bool RunCommand(size_t argc, char **argv) {
std::string outputPattern;
auto ParseOutputPattern = [&](size_t &argn) {
if(argn + 1 < argc && (!strcmp(argv[argn], "--output") ||
!strcmp(argv[argn], "-o"))) {
if(argn + 1 < args.size() && (args[argn] == "--output" ||
args[argn] == "-o")) {
argn++;
outputPattern = argv[argn];
outputPattern = args[argn];
return true;
} else return false;
};
Vector projUp, projRight;
Vector projUp = {}, projRight = {};
auto ParseViewDirection = [&](size_t &argn) {
if(argn + 1 < argc && (!strcmp(argv[argn], "--view") ||
!strcmp(argv[argn], "-v"))) {
if(argn + 1 < args.size() && (args[argn] == "--view" ||
args[argn] == "-v")) {
argn++;
if(!strcmp(argv[argn], "top")) {
if(args[argn] == "top") {
projRight = Vector::From(1, 0, 0);
projUp = Vector::From(0, 1, 0);
} else if(!strcmp(argv[argn], "bottom")) {
} else if(args[argn] == "bottom") {
projRight = Vector::From(-1, 0, 0);
projUp = Vector::From(0, 1, 0);
} else if(!strcmp(argv[argn], "left")) {
} else if(args[argn] == "left") {
projRight = Vector::From(0, 1, 0);
projUp = Vector::From(0, 0, 1);
} else if(!strcmp(argv[argn], "right")) {
} else if(args[argn] == "right") {
projRight = Vector::From(0, -1, 0);
projUp = Vector::From(0, 0, 1);
} else if(!strcmp(argv[argn], "front")) {
} else if(args[argn] == "front") {
projRight = Vector::From(-1, 0, 0);
projUp = Vector::From(0, 0, 1);
} else if(!strcmp(argv[argn], "back")) {
} else if(args[argn] == "back") {
projRight = Vector::From(1, 0, 0);
projUp = Vector::From(0, 0, 1);
} else if(!strcmp(argv[argn], "isometric")) {
} else if(args[argn] == "isometric") {
projRight = Vector::From(0.707, 0.000, -0.707);
projUp = Vector::From(-0.408, 0.816, -0.408);
} else {
fprintf(stderr, "Unrecognized view direction '%s'\n", argv[argn]);
fprintf(stderr, "Unrecognized view direction '%s'\n", args[argn].c_str());
}
return true;
} else return false;
@ -140,33 +140,33 @@ static bool RunCommand(size_t argc, char **argv) {
double chordTol = 1.0;
auto ParseChordTolerance = [&](size_t &argn) {
if(argn + 1 < argc && (!strcmp(argv[argn], "--chord-tol") ||
!strcmp(argv[argn], "-t"))) {
if(argn + 1 < args.size() && (args[argn] == "--chord-ol" ||
args[argn] == "-t")) {
argn++;
if(sscanf(argv[argn], "%lf", &chordTol) == 1) {
if(sscanf(args[argn].c_str(), "%lf", &chordTol) == 1) {
return true;
} else return false;
} else return false;
};
if(!strcmp(argv[1], "thumbnail")) {
unsigned width, height;
if(args[1] == "thumbnail") {
unsigned width = 0, height = 0;
auto ParseSize = [&](size_t &argn) {
if(argn + 1 < argc && !strcmp(argv[argn], "--size")) {
if(argn + 1 < args.size() && args[argn] == "--size") {
argn++;
if(sscanf(argv[argn], "%ux%u", &width, &height) == 2) {
if(sscanf(args[argn].c_str(), "%ux%u", &width, &height) == 2) {
return true;
} else return false;
} else return false;
};
for(size_t argn = 2; argn < argc; argn++) {
for(size_t argn = 2; argn < args.size(); argn++) {
if(!(ParseInputFile(argn) ||
ParseOutputPattern(argn) ||
ParseViewDirection(argn) ||
ParseChordTolerance(argn) ||
ParseSize(argn))) {
fprintf(stderr, "Unrecognized option '%s'.\n", argv[argn]);
fprintf(stderr, "Unrecognized option '%s'.\n", args[argn].c_str());
return false;
}
}
@ -193,13 +193,13 @@ static bool RunCommand(size_t argc, char **argv) {
PaintGraphics();
framebuffer->WritePng(output, /*flip=*/true);
};
} else if(!strcmp(argv[1], "export-view")) {
for(size_t argn = 2; argn < argc; argn++) {
} else if(args[1] == "export-view") {
for(size_t argn = 2; argn < args.size(); argn++) {
if(!(ParseInputFile(argn) ||
ParseOutputPattern(argn) ||
ParseViewDirection(argn) ||
ParseChordTolerance(argn))) {
fprintf(stderr, "Unrecognized option '%s'.\n", argv[argn]);
fprintf(stderr, "Unrecognized option '%s'.\n", args[argn].c_str());
return false;
}
}
@ -216,12 +216,12 @@ static bool RunCommand(size_t argc, char **argv) {
SS.ExportViewOrWireframeTo(output, /*exportWireframe=*/false);
};
} else if(!strcmp(argv[1], "export-wireframe")) {
for(size_t argn = 2; argn < argc; argn++) {
} else if(args[1] == "export-wireframe") {
for(size_t argn = 2; argn < args.size(); argn++) {
if(!(ParseInputFile(argn) ||
ParseOutputPattern(argn) ||
ParseChordTolerance(argn))) {
fprintf(stderr, "Unrecognized option '%s'.\n", argv[argn]);
fprintf(stderr, "Unrecognized option '%s'.\n", args[argn].c_str());
return false;
}
}
@ -231,12 +231,12 @@ static bool RunCommand(size_t argc, char **argv) {
SS.ExportViewOrWireframeTo(output, /*exportWireframe=*/true);
};
} else if(!strcmp(argv[1], "export-mesh")) {
for(size_t argn = 2; argn < argc; argn++) {
} else if(args[1] == "export-mesh") {
for(size_t argn = 2; argn < args.size(); argn++) {
if(!(ParseInputFile(argn) ||
ParseOutputPattern(argn) ||
ParseChordTolerance(argn))) {
fprintf(stderr, "Unrecognized option '%s'.\n", argv[argn]);
fprintf(stderr, "Unrecognized option '%s'.\n", args[argn].c_str());
return false;
}
}
@ -246,11 +246,11 @@ static bool RunCommand(size_t argc, char **argv) {
SS.ExportMeshTo(output);
};
} else if(!strcmp(argv[1], "export-surfaces")) {
for(size_t argn = 2; argn < argc; argn++) {
} else if(args[1] == "export-surfaces") {
for(size_t argn = 2; argn < args.size(); argn++) {
if(!(ParseInputFile(argn) ||
ParseOutputPattern(argn))) {
fprintf(stderr, "Unrecognized option '%s'.\n", argv[argn]);
fprintf(stderr, "Unrecognized option '%s'.\n", args[argn].c_str());
return false;
}
}
@ -260,7 +260,7 @@ static bool RunCommand(size_t argc, char **argv) {
sfw.ExportSurfacesTo(output);
};
} else {
fprintf(stderr, "Unrecognized command '%s'.\n", argv[1]);
fprintf(stderr, "Unrecognized command '%s'.\n", args[1].c_str());
return false;
}
@ -279,19 +279,22 @@ static bool RunCommand(size_t argc, char **argv) {
}
for(const std::string &inputFile : inputFiles) {
std::string absInputFile = PathFromCurrentDirectory(inputFile);
std::string outputFile = outputPattern;
size_t replaceAt = outputFile.find('%');
if(replaceAt != std::string::npos) {
outputFile.replace(replaceAt, 1, Basename(inputFile, /*stripExtension=*/true));
}
std::string absOutputFile = PathFromCurrentDirectory(outputFile);
SS.Init();
if(!SS.LoadFromFile(inputFile)) {
if(!SS.LoadFromFile(absInputFile)) {
fprintf(stderr, "Cannot load '%s'!\n", inputFile.c_str());
return false;
}
SS.AfterNewFile();
runner(outputFile);
runner(absOutputFile);
SK.Clear();
SS.Clear();
@ -302,14 +305,14 @@ static bool RunCommand(size_t argc, char **argv) {
}
int main(int argc, char **argv) {
InitPlatform();
std::vector<std::string> args = InitPlatform(argc, argv);
if(argc == 1) {
ShowUsage(argv[0]);
if(args.size() == 1) {
ShowUsage(args[0]);
return 0;
}
if(!RunCommand(argc, argv)) {
if(!RunCommand(args)) {
return 1;
} else {
return 0;

View File

@ -1161,7 +1161,7 @@ std::vector<std::string> SolveSpace::GetFontFiles() {
}
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename {
return SolveSpace::SS.OpenFile([filename UTF8String]);
return SolveSpace::SS.OpenFile(SolveSpace::PathFromCurrentDirectory([filename UTF8String]));
}
- (IBAction)preferences:(id)sender {

View File

@ -1590,7 +1590,7 @@ int main(int argc, char** argv) {
}
/* Make sure the argument is valid UTF-8. */
SS.OpenFile(Glib::ustring(argv[1]));
SS.OpenFile(PathFromCurrentDirectory(Glib::ustring(argv[1])));
}
main.run(*GW);

View File

@ -80,6 +80,12 @@ std::string PathSepUnixToPlatform(const std::string &filename)
return filename;
}
std::string PathFromCurrentDirectory(const std::string &relFilename)
{
// On Unix we can just pass this to ssfopen directly.
return relFilename;
}
FILE *ssfopen(const std::string &filename, const char *mode)
{
ssassert(filename.length() == strlen(filename.c_str()),
@ -251,8 +257,12 @@ void MemFree(void *p) {
free(p);
}
void InitPlatform(void) {
/* nothing to do */
std::vector<std::string> InitPlatform(int argc, char **argv) {
std::vector<std::string> args;
for(int i = 0; i < argc; i++) {
args.push_back(argv[i]);
}
return args;
}
};

View File

@ -1463,27 +1463,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
ShowWindow(TextWnd, SW_SHOWNOACTIVATE);
ShowWindow(GraphicsWnd, SW_SHOW);
// Create the heaps for all dynamic memory (AllocTemporary, MemAlloc)
InitPlatform();
// Pull out the Unicode command line.
int argc;
LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &argc);
// A filename may have been specified on the command line; if so, then
// strip any quotation marks, and make it absolute.
std::wstring filenameRel, filename;
if(argc >= 2) {
filenameRel = argv[1];
if(filenameRel[0] == L'\"' && filenameRel[filenameRel.length() - 1] == L'\"') {
filenameRel.erase(0, 1);
filenameRel.erase(filenameRel.length() - 1, 1);
}
DWORD len = GetFullPathNameW(&filenameRel[0], 0, NULL, NULL);
filename.resize(len - 1);
GetFullPathNameW(&filenameRel[0], len, &filename[0], NULL);
}
std::vector<std::string> args = InitPlatform(0, NULL);
#ifdef HAVE_SPACEWARE
// Initialize the SpaceBall, if present. Test if the driver is running
@ -1501,8 +1481,17 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
// Call in to the platform-independent code, and let them do their init
SS.Init();
if(!filename.empty())
SS.OpenFile(Narrow(filename));
// A filename may have been specified on the command line; if so, then
// strip any quotation marks, and make it absolute.
if(args.size() >= 2) {
std::string filename = args[1];
if(filename[0] == '\"' && filename[filename.length() - 1] == '\"') {
filename.erase(0, 1);
filename.erase(filename.length() - 1, 1);
}
SS.OpenFile(PathFromCurrentDirectory(filename));
}
// Repaint one more time, after we've set everything up.
PaintGraphics();

View File

@ -10,6 +10,7 @@
// Include after solvespace.h to avoid identifier clashes.
#include <windows.h>
#include <shellapi.h>
namespace SolveSpace {
static HANDLE PermHeap, TempHeap;
@ -118,6 +119,19 @@ std::string PathSepUnixToPlatform(const std::string &filename)
return result;
}
std::string PathFromCurrentDirectory(const std::string &relFilename)
{
// On Windows, ssfopen needs an absolute UNC path proper, so get that.
std::wstring relFilenameW = Widen(relFilename);
std::wstring absFilenameW;
absFilenameW.resize(GetFullPathNameW(relFilenameW.c_str(), 0, NULL, NULL));
DWORD length = GetFullPathNameW(relFilenameW.c_str(), absFilenameW.length(),
&absFilenameW[0], NULL);
ssassert(length != 0, "Expected GetFullPathName to succeed");
absFilenameW.resize(length);
return Narrow(absFilenameW);
}
static std::string MakeUNCFilename(const std::string &filename)
{
// Prepend \\?\ UNC prefix unless already an UNC path.
@ -192,7 +206,7 @@ void vl() {
ssassert(HeapValidate(PermHeap, HEAP_NO_SERIALIZE, NULL), "Corrupted heap");
}
void InitPlatform() {
std::vector<std::string> InitPlatform(int argc, char **argv) {
// Create the heap used for long-lived stuff (that gets freed piecewise).
PermHeap = HeapCreate(HEAP_NO_SERIALIZE, 1024*1024*20, 0);
// Create the heap that we use to store Exprs and other temp stuff.
@ -203,6 +217,17 @@ void InitPlatform() {
// and results in infinite WndProc recursion in GUI binaries.
_set_abort_behavior(0, _WRITE_ABORT_MSG);
#endif
// Extract the command-line arguments; the ones from main() are ignored,
// since they are in the OEM encoding.
int argcW;
LPWSTR *argvW = CommandLineToArgvW(GetCommandLineW(), &argcW);
std::vector<std::string> args;
for(int i = 0; i < argcW; i++) {
args.push_back(Narrow(argvW[i]));
}
LocalFree(argvW);
return args;
}
}

View File

@ -154,6 +154,7 @@ extern const bool FLIP_FRAMEBUFFER;
bool PathEqual(const std::string &a, const std::string &b);
std::string PathSepPlatformToUnix(const std::string &filename);
std::string PathSepUnixToPlatform(const std::string &filename);
std::string PathFromCurrentDirectory(const std::string &relFilename);
FILE *ssfopen(const std::string &filename, const char *mode);
std::fstream ssfstream(const std::string &filename, std::ios_base::openmode mode);
void ssremove(const std::string &filename);
@ -289,12 +290,13 @@ std::string CnfThawString(const std::string &val, const std::string &name);
uint32_t CnfThawInt(uint32_t val, const std::string &name);
float CnfThawFloat(float val, const std::string &name);
std::vector<std::string> InitPlatform(int argc, char **argv);
void *AllocTemporary(size_t n);
void FreeTemporary(void *p);
void FreeAllTemporary();
void *MemAlloc(size_t n);
void MemFree(void *p);
void InitPlatform();
void vl(); // debug function to validate heaps
#include "resource.h"

View File

@ -291,14 +291,14 @@ int Test::Case::Register(Test::Case testCase) {
}
int main(int argc, char **argv) {
InitPlatform();
std::vector<std::string> args = InitPlatform(argc, argv);
std::regex filter(".*");
if(argc == 1) {
} else if(argc == 2) {
filter = argv[1];
if(args.size() == 1) {
} else if(args.size() == 2) {
filter = args[1];
} else {
fprintf(stderr, "Usage: %s [test filter regex]\n", argv[0]);
fprintf(stderr, "Usage: %s [test filter regex]\n", args[0].c_str());
return 1;
}