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
parent
679a1f0ded
commit
4a0b4fd8d3
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue