solvespace/src/platform/w32util.cpp
whitequark e2e74762f4 Rework path and file operations to be more robust.
This commit updates a *lot* of rather questionable path handling
logic to be robust. Specifically:
  * All path operations go through Platform::Path.
  * All ad-hoc path handling functions are removed, together with
    PATH_SEP. This removes code that was in platform-independent
    parts, but had platform-dependent behavior.
  * Group::linkFileRel is removed; only an absolute path is stored
    in Group::linkFile. However, only Group::linkFileRel is saved,
    with the relative path calculated on the fly, from the filename
    passed into SaveToFile. This eliminates dependence on global
    state, and makes it unnecessary to have separare code paths
    for saved and not yet saved files.
  * In a departure from previous practice, functions with
    platform-independent code but platform-dependent behavior
    are all grouped under platform/. This makes it easy to grep
    for functions with platform-dependent behavior.
  * Similarly, new (GUI-independent) code for all platforms is added
    in the same platform.cpp file, guarded with #ifs. It turns out
    that implementations for different platforms had a lot of shared
    code that tended to go out of sync.
2017-03-11 18:58:53 +00:00

117 lines
3.9 KiB
C++

//-----------------------------------------------------------------------------
// Utility functions that depend on Win32. Notably, our memory allocation;
// we use two separate allocators, one for long-lived stuff and one for
// stuff that gets freed after every regeneration of the model, to save us
// the trouble of freeing the latter explicitly.
//
// Copyright 2008-2013 Jonathan Westhues.
//-----------------------------------------------------------------------------
#include "solvespace.h"
// Include after solvespace.h to avoid identifier clashes.
#include <windows.h>
#include <shellapi.h>
namespace SolveSpace {
static HANDLE PermHeap, TempHeap;
void dbp(const char *str, ...)
{
va_list f;
static char buf[1024*50];
va_start(f, str);
_vsnprintf(buf, sizeof(buf), str, f);
va_end(f);
// The native version of OutputDebugString, unlike most others,
// is OutputDebugStringA.
OutputDebugStringA(buf);
OutputDebugStringA("\n");
#ifndef NDEBUG
// Duplicate to stderr in debug builds, but not in release; this is slow.
fputs(buf, stderr);
fputc('\n', stderr);
#endif
}
void assert_failure(const char *file, unsigned line, const char *function,
const char *condition, const char *message) {
dbp("File %s, line %u, function %s:", file, line, function);
dbp("Assertion '%s' failed: ((%s) == false).", message, condition);
#ifdef NDEBUG
_exit(1);
#else
abort();
#endif
}
//-----------------------------------------------------------------------------
// A separate heap, on which we allocate expressions. Maybe a bit faster,
// since no fragmentation issues whatsoever, and it also makes it possible
// to be sloppy with our memory management, and just free everything at once
// at the end.
//-----------------------------------------------------------------------------
void *AllocTemporary(size_t n)
{
void *v = HeapAlloc(TempHeap, HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, n);
ssassert(v != NULL, "Cannot allocate memory");
return v;
}
void FreeTemporary(void *p) {
HeapFree(TempHeap, HEAP_NO_SERIALIZE, p);
}
void FreeAllTemporary()
{
if(TempHeap) HeapDestroy(TempHeap);
TempHeap = HeapCreate(HEAP_NO_SERIALIZE, 1024*1024*20, 0);
// This is a good place to validate, because it gets called fairly
// often.
vl();
}
void *MemAlloc(size_t n) {
void *p = HeapAlloc(PermHeap, HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, n);
ssassert(p != NULL, "Cannot allocate memory");
return p;
}
void MemFree(void *p) {
HeapFree(PermHeap, HEAP_NO_SERIALIZE, p);
}
void vl() {
ssassert(HeapValidate(TempHeap, HEAP_NO_SERIALIZE, NULL), "Corrupted heap");
ssassert(HeapValidate(PermHeap, HEAP_NO_SERIALIZE, NULL), "Corrupted heap");
}
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.
FreeAllTemporary();
#if !defined(LIBRARY) && defined(_MSC_VER)
// Don't display the abort message; it is aggravating in CLI binaries
// and results in infinite WndProc recursion in GUI binaries.
_set_abort_behavior(0, _WRITE_ABORT_MSG);
int crtReportTypes[] = {_CRT_WARN, _CRT_ERROR, _CRT_ASSERT};
for(int crtReportType : crtReportTypes) {
_CrtSetReportMode(crtReportType, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
_CrtSetReportFile(crtReportType, _CRTDBG_FILE_STDERR);
}
#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(Platform::Narrow(argvW[i]));
}
LocalFree(argvW);
return args;
}
}