Rewrite all path handling with std::string.

What do we gain from this? Several things.

 * First, usage of PATH_MAX (the POSIX constant) is eliminated.
   PATH_MAX is actually a lie; Linux and OS X (and probably other BSDs
   too) do not have an actual path length limit. Linux claims 4096,
   OS X claims 1024, but it is trivial to construct paths that are
   longer.

 * Second, while Windows does enforce a limit of MAX_PATH (the Win32
   constant) for its ASCII functions, the Unicode variants, when
   used with UNC paths, do not have this restriction.
   The capability to use UNC paths is useful by itself, as it allows
   to access files on network shares directly.

 * Third, representing paths as std::string will make it easier to
   interoperate with *W WinAPI functions later.
pull/4/head
whitequark 2015-12-27 09:03:24 +08:00
parent 3ffbac38c6
commit 32383d22bf
17 changed files with 309 additions and 328 deletions

View File

@ -19,8 +19,6 @@
using SolveSpace::dbp; using SolveSpace::dbp;
char SolveSpace::RecentFile[MAX_RECENT][MAX_PATH];
#define GL_CHECK() \ #define GL_CHECK() \
do { \ do { \
int err = (int)glGetError(); \ int err = (int)glGetError(); \
@ -472,9 +470,9 @@ void PaintGraphics(void) {
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, YES); CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, YES);
} }
void SetCurrentFilename(const char *filename) { void SetCurrentFilename(const std::string &filename) {
if(filename) { if(!filename.empty()) {
[GW setTitleWithRepresentedFilename:[NSString stringWithUTF8String:filename]]; [GW setTitleWithRepresentedFilename:[NSString stringWithUTF8String:filename.c_str()]];
} else { } else {
[GW setTitle:@"(new sketch)"]; [GW setTitle:@"(new sketch)"];
[GW setRepresentedFilename:@""]; [GW setRepresentedFilename:@""];
@ -679,7 +677,7 @@ static void RefreshRecentMenu(int id_, int base) {
break; break;
NSMenuItem *item = [[NSMenuItem alloc] NSMenuItem *item = [[NSMenuItem alloc]
initWithTitle:[[NSString stringWithUTF8String:RecentFile[i]] initWithTitle:[[NSString stringWithUTF8String:RecentFile[i].c_str()]
stringByAbbreviatingWithTildeInPath] stringByAbbreviatingWithTildeInPath]
action:nil keyEquivalent:@""]; action:nil keyEquivalent:@""];
[item setTag:(base + i)]; [item setTag:(base + i)];
@ -706,7 +704,7 @@ bool MenuBarIsVisible(void) {
/* Save/load */ /* Save/load */
bool SolveSpace::GetOpenFile(char *file, const char *defExtension, const char *selPattern) { bool SolveSpace::GetOpenFile(std::string &file, const char *defExtension, const char *selPattern) {
NSOpenPanel *panel = [NSOpenPanel openPanel]; NSOpenPanel *panel = [NSOpenPanel openPanel];
NSMutableArray *filters = [[NSMutableArray alloc] init]; NSMutableArray *filters = [[NSMutableArray alloc] init];
for(NSString *filter in [[NSString stringWithUTF8String:selPattern] for(NSString *filter in [[NSString stringWithUTF8String:selPattern]
@ -719,8 +717,8 @@ bool SolveSpace::GetOpenFile(char *file, const char *defExtension, const char *s
[panel setAllowedFileTypes:filters]; [panel setAllowedFileTypes:filters];
if([panel runModal] == NSFileHandlingPanelOKButton) { if([panel runModal] == NSFileHandlingPanelOKButton) {
strcpy(file, [[NSFileManager defaultManager] file = [[NSFileManager defaultManager]
fileSystemRepresentationWithPath:[[panel URL] path]]); fileSystemRepresentationWithPath:[[panel URL] path]];
return true; return true;
} else { } else {
return false; return false;
@ -747,7 +745,7 @@ bool SolveSpace::GetOpenFile(char *file, const char *defExtension, const char *s
} }
@end @end
bool SolveSpace::GetSaveFile(char *file, const char *defExtension, const char *selPattern) { bool SolveSpace::GetSaveFile(std::string &file, const char *defExtension, const char *selPattern) {
NSSavePanel *panel = [NSSavePanel savePanel]; NSSavePanel *panel = [NSSavePanel savePanel];
[panel setNameFieldStringValue:[@"untitled" [panel setNameFieldStringValue:[@"untitled"
stringByAppendingPathExtension:[NSString stringWithUTF8String:defExtension]]]; stringByAppendingPathExtension:[NSString stringWithUTF8String:defExtension]]];
@ -777,8 +775,8 @@ bool SolveSpace::GetSaveFile(char *file, const char *defExtension, const char *s
indexOfObject:[NSString stringWithUTF8String:defExtension]]]; indexOfObject:[NSString stringWithUTF8String:defExtension]]];
if([panel runModal] == NSFileHandlingPanelOKButton) { if([panel runModal] == NSFileHandlingPanelOKButton) {
strcpy(file, [[NSFileManager defaultManager] file = [[NSFileManager defaultManager]
fileSystemRepresentationWithPath:[[panel URL] path]]); fileSystemRepresentationWithPath:[[panel URL] path]];
return true; return true;
} else { } else {
return false; return false;
@ -791,7 +789,7 @@ int SolveSpace::SaveFileYesNoCancel(void) {
[alert setMessageText: [alert setMessageText:
[[@"Do you want to save the changes you made to the sketch “" [[@"Do you want to save the changes you made to the sketch “"
stringByAppendingString: stringByAppendingString:
[[NSString stringWithUTF8String:SolveSpace::SS.saveFile] [[NSString stringWithUTF8String:SolveSpace::SS.saveFile.c_str()]
stringByAbbreviatingWithTildeInPath]] stringByAbbreviatingWithTildeInPath]]
stringByAppendingString:@"”?"]]; stringByAppendingString:@"”?"]];
} else { } else {
@ -1065,8 +1063,8 @@ void SolveSpace::LoadAllFontFiles(void) {
NSString *fontPath = [NSString stringWithString:[(NSURL *)CFBridgingRelease(url) path]]; NSString *fontPath = [NSString stringWithString:[(NSURL *)CFBridgingRelease(url) path]];
if([[fontPath pathExtension] isEqual:@"ttf"]) { if([[fontPath pathExtension] isEqual:@"ttf"]) {
TtfFont tf = {}; TtfFont tf = {};
strcpy(tf.fontFile, [[NSFileManager defaultManager] tf.fontFile = [[NSFileManager defaultManager]
fileSystemRepresentationWithPath:fontPath]); fileSystemRepresentationWithPath:fontPath];
SS.fonts.l.Add(&tf); SS.fonts.l.Add(&tf);
} }
} }

View File

@ -35,7 +35,7 @@ void TextWindow::ScreenSetTtfFont(int link, uint32_t v) {
if(!r) return; if(!r) return;
SS.UndoRemember(); SS.UndoRemember();
r->font.strcpy(SS.fonts.l.elem[i].FontFileBaseName()); r->font.strcpy(SS.fonts.l.elem[i].FontFileBaseName().c_str());
SS.MarkGroupDirty(r->group); SS.MarkGroupDirty(r->group);
SS.ScheduleGenerateAll(); SS.ScheduleGenerateAll();
SS.ScheduleShowTW(); SS.ScheduleShowTW();
@ -178,7 +178,7 @@ void TextWindow::DescribeSelection(void) {
int i; int i;
for(i = 0; i < SS.fonts.l.n; i++) { for(i = 0; i < SS.fonts.l.n; i++) {
TtfFont *tf = &(SS.fonts.l.elem[i]); TtfFont *tf = &(SS.fonts.l.elem[i]);
if(strcmp(e->font.str, tf->FontFileBaseName())==0) { if(strcmp(e->font.str, tf->FontFileBaseName().c_str())==0) {
Printf(false, "%Bp %s", Printf(false, "%Bp %s",
(i & 1) ? 'd' : 'a', (i & 1) ? 'd' : 'a',
tf->name.str); tf->name.str);

View File

@ -9,7 +9,7 @@
#include "solvespace.h" #include "solvespace.h"
#include <png.h> #include <png.h>
void SolveSpaceUI::ExportSectionTo(const char *filename) { void SolveSpaceUI::ExportSectionTo(const std::string &filename) {
Vector gn = (SS.GW.projRight).Cross(SS.GW.projUp); Vector gn = (SS.GW.projRight).Cross(SS.GW.projUp);
gn = gn.WithMagnitude(1); gn = gn.WithMagnitude(1);
@ -107,7 +107,7 @@ void SolveSpaceUI::ExportSectionTo(const char *filename) {
bl.Clear(); bl.Clear();
} }
void SolveSpaceUI::ExportViewOrWireframeTo(const char *filename, bool wireframe) { void SolveSpaceUI::ExportViewOrWireframeTo(const std::string &filename, bool wireframe) {
int i; int i;
SEdgeList edges = {}; SEdgeList edges = {};
SBezierList beziers = {}; SBezierList beziers = {};
@ -389,27 +389,27 @@ double VectorFileWriter::MmToPts(double mm) {
return (mm/25.4)*72; return (mm/25.4)*72;
} }
VectorFileWriter *VectorFileWriter::ForFile(const char *filename) { VectorFileWriter *VectorFileWriter::ForFile(const std::string &filename) {
VectorFileWriter *ret; VectorFileWriter *ret;
if(StringEndsIn(filename, ".dxf")) { if(FilenameHasExtension(filename, ".dxf")) {
static DxfFileWriter DxfWriter; static DxfFileWriter DxfWriter;
ret = &DxfWriter; ret = &DxfWriter;
} else if(StringEndsIn(filename, ".ps") || StringEndsIn(filename, ".eps")) { } else if(FilenameHasExtension(filename, ".ps") || FilenameHasExtension(filename, ".eps")) {
static EpsFileWriter EpsWriter; static EpsFileWriter EpsWriter;
ret = &EpsWriter; ret = &EpsWriter;
} else if(StringEndsIn(filename, ".pdf")) { } else if(FilenameHasExtension(filename, ".pdf")) {
static PdfFileWriter PdfWriter; static PdfFileWriter PdfWriter;
ret = &PdfWriter; ret = &PdfWriter;
} else if(StringEndsIn(filename, ".svg")) { } else if(FilenameHasExtension(filename, ".svg")) {
static SvgFileWriter SvgWriter; static SvgFileWriter SvgWriter;
ret = &SvgWriter; ret = &SvgWriter;
} else if(StringEndsIn(filename, ".plt")||StringEndsIn(filename, ".hpgl")) { } else if(FilenameHasExtension(filename, ".plt")||FilenameHasExtension(filename, ".hpgl")) {
static HpglFileWriter HpglWriter; static HpglFileWriter HpglWriter;
ret = &HpglWriter; ret = &HpglWriter;
} else if(StringEndsIn(filename, ".step")||StringEndsIn(filename, ".stp")) { } else if(FilenameHasExtension(filename, ".step")||FilenameHasExtension(filename, ".stp")) {
static Step2dFileWriter Step2dWriter; static Step2dFileWriter Step2dWriter;
ret = &Step2dWriter; ret = &Step2dWriter;
} else if(StringEndsIn(filename, ".txt")) { } else if(FilenameHasExtension(filename, ".txt")) {
static GCodeFileWriter GCodeWriter; static GCodeFileWriter GCodeWriter;
ret = &GCodeWriter; ret = &GCodeWriter;
} else { } else {
@ -417,13 +417,13 @@ VectorFileWriter *VectorFileWriter::ForFile(const char *filename) {
"filename '%s'; try " "filename '%s'; try "
".step, .stp, .dxf, .svg, .plt, .hpgl, .pdf, .txt, " ".step, .stp, .dxf, .svg, .plt, .hpgl, .pdf, .txt, "
".eps, or .ps.", ".eps, or .ps.",
filename); filename.c_str());
return NULL; return NULL;
} }
FILE *f = fopen(filename, "wb"); FILE *f = fopen(filename.c_str(), "wb");
if(!f) { if(!f) {
Error("Couldn't write to '%s'", filename); Error("Couldn't write to '%s'", filename.c_str());
return NULL; return NULL;
} }
ret->f = f; ret->f = f;
@ -558,29 +558,29 @@ void VectorFileWriter::BezierAsNonrationalCubic(SBezier *sb, int depth) {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Export a triangle mesh, in the requested format. // Export a triangle mesh, in the requested format.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void SolveSpaceUI::ExportMeshTo(const char *filename) { void SolveSpaceUI::ExportMeshTo(const std::string &filename) {
SMesh *m = &(SK.GetGroup(SS.GW.activeGroup)->displayMesh); SMesh *m = &(SK.GetGroup(SS.GW.activeGroup)->displayMesh);
if(m->IsEmpty()) { if(m->IsEmpty()) {
Error("Active group mesh is empty; nothing to export."); Error("Active group mesh is empty; nothing to export.");
return; return;
} }
FILE *f = fopen(filename, "wb"); FILE *f = fopen(filename.c_str(), "wb");
if(!f) { if(!f) {
Error("Couldn't write to '%s'", filename); Error("Couldn't write to '%s'", filename.c_str());
return; return;
} }
if(StringEndsIn(filename, ".stl")) { if(FilenameHasExtension(filename, ".stl")) {
ExportMeshAsStlTo(f, m); ExportMeshAsStlTo(f, m);
} else if(StringEndsIn(filename, ".obj")) { } else if(FilenameHasExtension(filename, ".obj")) {
ExportMeshAsObjTo(f, m); ExportMeshAsObjTo(f, m);
} else if(StringEndsIn(filename, ".js")) { } else if(FilenameHasExtension(filename, ".js")) {
SEdgeList *e = &(SK.GetGroup(SS.GW.activeGroup)->displayEdges); SEdgeList *e = &(SK.GetGroup(SS.GW.activeGroup)->displayEdges);
ExportMeshAsThreeJsTo(f, filename, m, e); ExportMeshAsThreeJsTo(f, filename, m, e);
} else { } else {
Error("Can't identify output file type from file extension of " Error("Can't identify output file type from file extension of "
"filename '%s'; try .stl, .obj, .js.", filename); "filename '%s'; try .stl, .obj, .js.", filename.c_str());
} }
fclose(f); fclose(f);
@ -658,7 +658,7 @@ void SolveSpaceUI::ExportMeshAsObjTo(FILE *f, SMesh *sm) {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Export the mesh as a JavaScript script, which is compatible with Three.js. // Export the mesh as a JavaScript script, which is compatible with Three.js.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void SolveSpaceUI::ExportMeshAsThreeJsTo(FILE *f, const char * filename, SMesh *sm, void SolveSpaceUI::ExportMeshAsThreeJsTo(FILE *f, const std::string &filename, SMesh *sm,
SEdgeList *sel) SEdgeList *sel)
{ {
SPointList spl = {}; SPointList spl = {};
@ -871,32 +871,32 @@ void SolveSpaceUI::ExportMeshAsThreeJsTo(FILE *f, const char * filename, SMesh *
double largerBoundXY = max((bndh.x - bndl.x), (bndh.y - bndl.y)); double largerBoundXY = max((bndh.x - bndl.x), (bndh.y - bndl.y));
double largerBoundZ = max(largerBoundXY, (bndh.z - bndl.z + 1)); double largerBoundZ = max(largerBoundXY, (bndh.z - bndl.z + 1));
char *baseFilename = (char *) MemAlloc(strlen(filename)); std::string baseFilename = filename;
const char *lastSlash;
#ifdef WIN32 #ifdef WIN32
lastSlash = strrchr(filename, '\\'); size_t lastSlash = baseFilename.rfind('\\');
#else #else
lastSlash = strrchr(filename, '/'); size_t lastSlash = baseFilename.rfind('/');
#endif #endif
if(!lastSlash) oops(); if(lastSlash == std::string::npos) oops();
lastSlash++; // Point one past last slash. baseFilename.erase(0, lastSlash + 1);
strcpy(baseFilename, lastSlash); // Copy the file w/ extension.
*strrchr(baseFilename, '.') = '\0'; // Strip extension.
for(int i = 0; i < strlen(baseFilename); i++) { size_t dot = baseFilename.rfind('.');
baseFilename.erase(dot);
for(int i = 0; i < baseFilename.length(); i++) {
if(!isalpha(baseFilename[i]) && if(!isalpha(baseFilename[i]) &&
/* also permit UTF-8 */ !((unsigned char)baseFilename[i] >= 0x80)) /* also permit UTF-8 */ !((unsigned char)baseFilename[i] >= 0x80))
baseFilename[i] = '_'; baseFilename[i] = '_';
} }
fprintf(f, html, baseFilename, baseFilename); fprintf(f, html, baseFilename.c_str(), baseFilename.c_str());
fprintf(f, "var three_js_%s = {\n" fprintf(f, "var three_js_%s = {\n"
" bounds: {\n" " bounds: {\n"
" x: %f, y: %f, near: %f, far: %f, z: %f, edgeBias: %f\n" " x: %f, y: %f, near: %f, far: %f, z: %f, edgeBias: %f\n"
" },\n", " },\n",
baseFilename, baseFilename.c_str(),
largerBoundXY, largerBoundXY,
largerBoundXY, largerBoundXY,
1.0, 1.0,
@ -904,8 +904,6 @@ void SolveSpaceUI::ExportMeshAsThreeJsTo(FILE *f, const char * filename, SMesh *
largerBoundZ, largerBoundZ,
largerBoundZ / 250); largerBoundZ / 250);
MemFree(baseFilename);
// Output lighting information. // Output lighting information.
fputs(" lights: {\n" fputs(" lights: {\n"
" d: [\n", f); " d: [\n", f);
@ -994,7 +992,7 @@ void SolveSpaceUI::ExportMeshAsThreeJsTo(FILE *f, const char * filename, SMesh *
// Export a view of the model as an image; we just take a screenshot, by // Export a view of the model as an image; we just take a screenshot, by
// rendering the view in the usual way and then copying the pixels. // rendering the view in the usual way and then copying the pixels.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void SolveSpaceUI::ExportAsPngTo(const char *filename) { void SolveSpaceUI::ExportAsPngTo(const std::string &filename) {
int w = (int)SS.GW.width, h = (int)SS.GW.height; int w = (int)SS.GW.width, h = (int)SS.GW.height;
// No guarantee that the back buffer contains anything valid right now, // No guarantee that the back buffer contains anything valid right now,
// so repaint the scene. And hide the toolbar too. // so repaint the scene. And hide the toolbar too.
@ -1003,7 +1001,7 @@ void SolveSpaceUI::ExportAsPngTo(const char *filename) {
SS.GW.Paint(); SS.GW.Paint();
SS.showToolbar = prevShowToolbar; SS.showToolbar = prevShowToolbar;
FILE *f = fopen(filename, "wb"); FILE *f = fopen(filename.c_str(), "wb");
if(!f) goto err; if(!f) goto err;
png_struct *png_ptr; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, png_struct *png_ptr; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
@ -1046,7 +1044,7 @@ void SolveSpaceUI::ExportAsPngTo(const char *filename) {
return; return;
err: err:
Error("Error writing PNG file '%s'", filename); Error("Error writing PNG file '%s'", filename.c_str());
if(f) fclose(f); if(f) fclose(f);
return; return;
} }

View File

@ -292,7 +292,7 @@ void StepFileWriter::WriteFooter(void) {
); );
} }
void StepFileWriter::ExportSurfacesTo(char *file) { void StepFileWriter::ExportSurfacesTo(const std::string &filename) {
Group *g = SK.GetGroup(SS.GW.activeGroup); Group *g = SK.GetGroup(SS.GW.activeGroup);
SShell *shell = &(g->runningShell); SShell *shell = &(g->runningShell);
@ -305,9 +305,9 @@ void StepFileWriter::ExportSurfacesTo(char *file) {
return; return;
} }
f = fopen(file, "wb"); f = fopen(filename.c_str(), "wb");
if(!f) { if(!f) {
Error("Couldn't write to '%s'", file); Error("Couldn't write to '%s'", filename.c_str());
return; return;
} }

View File

@ -201,7 +201,7 @@ const SolveSpaceUI::SaveTable SolveSpaceUI::SAVED[] = {
union SAVEDptr { union SAVEDptr {
IdList<EntityMap,EntityId> M; IdList<EntityMap,EntityId> M;
NameStr N; NameStr N;
char P[MAX_PATH]; /* std::string P */
bool b; bool b;
RgbaColor c; RgbaColor c;
int d; int d;
@ -225,7 +225,7 @@ void SolveSpaceUI::SaveUsingTable(int type) {
fprintf(fh, "%s=", SAVED[i].desc); fprintf(fh, "%s=", SAVED[i].desc);
switch(fmt) { switch(fmt) {
case 'N': fprintf(fh, "%s", p->N.str); break; case 'N': fprintf(fh, "%s", p->N.str); break;
case 'P': fprintf(fh, "%s", p->P); break; case 'P': fprintf(fh, "%s", ((std::string*)p)->c_str()); break;
case 'b': fprintf(fh, "%d", p->b ? 1 : 0); break; case 'b': fprintf(fh, "%d", p->b ? 1 : 0); break;
case 'c': fprintf(fh, "%08x", p->c.ToPackedInt()); break; case 'c': fprintf(fh, "%08x", p->c.ToPackedInt()); break;
case 'd': fprintf(fh, "%d", p->d); break; case 'd': fprintf(fh, "%d", p->d); break;
@ -250,7 +250,7 @@ void SolveSpaceUI::SaveUsingTable(int type) {
} }
} }
bool SolveSpaceUI::SaveToFile(const char *filename) { bool SolveSpaceUI::SaveToFile(const std::string &filename) {
// Make sure all the entities are regenerated up to date, since they // Make sure all the entities are regenerated up to date, since they
// will be exported. We reload the imported files because that rewrites // will be exported. We reload the imported files because that rewrites
// the impFileRel for our possibly-new filename. // the impFileRel for our possibly-new filename.
@ -258,9 +258,9 @@ bool SolveSpaceUI::SaveToFile(const char *filename) {
SS.ReloadAllImported(); SS.ReloadAllImported();
SS.GenerateAll(0, INT_MAX); SS.GenerateAll(0, INT_MAX);
fh = fopen(filename, "wb"); fh = fopen(filename.c_str(), "wb");
if(!fh) { if(!fh) {
Error("Couldn't write to file '%s'", filename); Error("Couldn't write to file '%s'", filename.c_str());
return false; return false;
} }
@ -385,7 +385,7 @@ void SolveSpaceUI::LoadUsingTable(char *key, char *val) {
break; break;
case 'P': case 'P':
if(strlen(val)+1 < MAX_PATH) strcpy(p->P, val); *((std::string*)p) = val;
break; break;
case 'M': { case 'M': {
@ -420,13 +420,13 @@ void SolveSpaceUI::LoadUsingTable(char *key, char *val) {
} }
} }
bool SolveSpaceUI::LoadFromFile(const char *filename) { bool SolveSpaceUI::LoadFromFile(const std::string &filename) {
allConsistent = false; allConsistent = false;
fileLoadError = false; fileLoadError = false;
fh = fopen(filename, "rb"); fh = fopen(filename.c_str(), "rb");
if(!fh) { if(!fh) {
Error("Couldn't read from file '%s'", filename); Error("Couldn't read from file '%s'", filename.c_str());
return false; return false;
} }
@ -503,13 +503,13 @@ bool SolveSpaceUI::LoadFromFile(const char *filename) {
return true; return true;
} }
bool SolveSpaceUI::LoadEntitiesFromFile(const char *file, EntityList *le, bool SolveSpaceUI::LoadEntitiesFromFile(const std::string &filename, EntityList *le,
SMesh *m, SShell *sh) SMesh *m, SShell *sh)
{ {
SSurface srf = {}; SSurface srf = {};
SCurve crv = {}; SCurve crv = {};
fh = fopen(file, "rb"); fh = fopen(filename.c_str(), "rb");
if(!fh) return false; if(!fh) return false;
le->Clear(); le->Clear();
@ -652,7 +652,7 @@ void SolveSpaceUI::ReloadAllImported(void) {
// Change backslashes to forward slashes on Unix. // Change backslashes to forward slashes on Unix.
// Done unconditionally to get the displayed filename // Done unconditionally to get the displayed filename
// consistent with current filesystem type. // consistent with current filesystem type.
for(int j = 0; j < strlen(g->impFileRel); j++) { for(int j = 0; j < g->impFileRel.length(); j++) {
if(g->impFileRel[j] == '\\') if(g->impFileRel[j] == '\\')
g->impFileRel[j] = '/'; g->impFileRel[j] = '/';
} }
@ -662,39 +662,35 @@ void SolveSpaceUI::ReloadAllImported(void) {
g->impMesh.Clear(); g->impMesh.Clear();
g->impShell.Clear(); g->impShell.Clear();
FILE *test = fopen(g->impFile, "rb"); FILE *test = fopen(g->impFile.c_str(), "rb");
if(test) { if(test) {
fclose(test); // okay, exists fclose(test); // okay, exists
} else { } else {
// It doesn't exist. Perhaps the entire tree has moved, and we // It doesn't exist. Perhaps the entire tree has moved, and we
// can use the relative filename to get us back. // can use the relative filename to get us back.
if(SS.saveFile[0]) { if(!SS.saveFile.empty()) {
char fromRel[MAX_PATH]; std::string fromRel = MakePathAbsolute(SS.saveFile, g->impFileRel);
strcpy(fromRel, g->impFileRel); test = fopen(fromRel.c_str(), "rb");
MakePathAbsolute(SS.saveFile, fromRel);
test = fopen(fromRel, "rb");
if(test) { if(test) {
fclose(test); fclose(test);
// It worked, this is our new absolute path // It worked, this is our new absolute path
strcpy(g->impFile, fromRel); g->impFile = fromRel;
} }
} }
} }
if(LoadEntitiesFromFile(g->impFile, if(LoadEntitiesFromFile(g->impFile, &(g->impEntity), &(g->impMesh), &(g->impShell)))
&(g->impEntity), &(g->impMesh), &(g->impShell)))
{ {
if(SS.saveFile[0]) { if(!SS.saveFile.empty()) {
// Record the imported file's name relative to our filename; // Record the imported file's name relative to our filename;
// if the entire tree moves, then everything will still work // if the entire tree moves, then everything will still work
strcpy(g->impFileRel, g->impFile); g->impFileRel = MakePathRelative(SS.saveFile, g->impFile);
MakePathRelative(SS.saveFile, g->impFileRel);
} else { } else {
// We're not yet saved, so can't make it absolute // We're not yet saved, so can't make it absolute
strcpy(g->impFileRel, g->impFile); g->impFileRel = g->impFile;
} }
} else { } else {
Error("Failed to load imported file '%s'", g->impFile); Error("Failed to load imported file '%s'", g->impFile.c_str());
} }
} }
} }

View File

@ -57,7 +57,7 @@ void Group::MenuGroup(int id) {
g.scale = 1; g.scale = 1;
if(id >= RECENT_IMPORT && id < (RECENT_IMPORT + MAX_RECENT)) { if(id >= RECENT_IMPORT && id < (RECENT_IMPORT + MAX_RECENT)) {
strcpy(g.impFile, RecentFile[id-RECENT_IMPORT]); g.impFile = RecentFile[id-RECENT_IMPORT];
id = GraphicsWindow::MNU_GROUP_IMPORT; id = GraphicsWindow::MNU_GROUP_IMPORT;
} }
@ -187,30 +187,36 @@ void Group::MenuGroup(int id) {
case GraphicsWindow::MNU_GROUP_IMPORT: { case GraphicsWindow::MNU_GROUP_IMPORT: {
g.type = IMPORTED; g.type = IMPORTED;
g.opA = SS.GW.activeGroup; g.opA = SS.GW.activeGroup;
if(strlen(g.impFile) == 0) { if(g.impFile.empty()) {
if(!GetOpenFile(g.impFile, SLVS_EXT, SLVS_PATTERN)) return; if(!GetOpenFile(g.impFile, SLVS_EXT, SLVS_PATTERN)) return;
} }
// Assign the default name of the group based on the name of // Assign the default name of the group based on the name of
// the imported file. // the imported file.
char groupName[MAX_PATH]; std::string groupName = g.impFile;
strcpy(groupName, g.impFile); size_t pos;
char *dot = strrchr(groupName, '.');
if(dot) *dot = '\0';
char *s, *start = groupName; pos = groupName.rfind('.');
for(s = groupName; *s; s++) { if(pos != std::string::npos)
if(*s == '/' || *s == '\\') { groupName.erase(pos);
start = s + 1; pos = groupName.find('/');
} else if(isalnum(*s)) { if(pos != std::string::npos)
groupName.erase(0, pos);
pos = groupName.find('\\');
if(pos != std::string::npos)
groupName.erase(0, pos);
for(int i = 0; i < groupName.length(); i++) {
if(isalnum(groupName[i])) {
// do nothing, valid character // do nothing, valid character
} else { } else {
// convert invalid characters (like spaces) to dashes // convert invalid characters (like spaces) to dashes
*s = '-'; groupName[i] = '-';
} }
} }
if(strlen(start) > 0) {
g.name.strcpy(start); if(groupName.length() > 0) {
g.name.strcpy(groupName.substr(0, 64).c_str());
} else { } else {
g.name.strcpy("import"); g.name.strcpy("import");
} }

View File

@ -63,15 +63,6 @@
#endif #endif
namespace SolveSpace { namespace SolveSpace {
char RecentFile[MAX_RECENT][MAX_PATH];
#define GL_CHECK() \
do { \
int err = (int)glGetError(); \
if(err) dbp("%s:%d: glGetError() == 0x%X %s", \
__FILE__, __LINE__, err, gluErrorString(err)); \
} while (0)
/* Settings */ /* Settings */
/* Why not just use GSettings? Two reasons. It doesn't allow to easily see /* Why not just use GSettings? Two reasons. It doesn't allow to easily see
@ -240,6 +231,13 @@ void ScheduleLater() {
/* GL wrapper */ /* GL wrapper */
#define GL_CHECK() \
do { \
int err = (int)glGetError(); \
if(err) dbp("%s:%d: glGetError() == 0x%X %s", \
__FILE__, __LINE__, err, gluErrorString(err)); \
} while (0)
class GlWidget : public Gtk::DrawingArea { class GlWidget : public Gtk::DrawingArea {
public: public:
GlWidget() : _offscreen(NULL) { GlWidget() : _offscreen(NULL) {
@ -703,9 +701,9 @@ void PaintGraphics(void) {
Glib::MainContext::get_default()->iteration(false); Glib::MainContext::get_default()->iteration(false);
} }
void SetCurrentFilename(const char *filename) { void SetCurrentFilename(const std::string &filename) {
if(filename) { if(!filename.empty()) {
GW->set_title(std::string("SolveSpace - ") + filename); GW->set_title("SolveSpace - " + filename);
} else { } else {
GW->set_title("SolveSpace - (not yet saved)"); GW->set_title("SolveSpace - (not yet saved)");
} }
@ -1078,7 +1076,7 @@ static void FiltersFromPattern(const char *active, const char *patterns,
} }
} }
bool GetOpenFile(char *file, const char *active, const char *patterns) { bool GetOpenFile(std::string &file, const char *active, const char *patterns) {
Gtk::FileChooserDialog chooser(*GW, "SolveSpace - Open File"); Gtk::FileChooserDialog chooser(*GW, "SolveSpace - Open File");
chooser.set_filename(file); chooser.set_filename(file);
chooser.add_button("_Cancel", Gtk::RESPONSE_CANCEL); chooser.add_button("_Cancel", Gtk::RESPONSE_CANCEL);
@ -1088,8 +1086,8 @@ bool GetOpenFile(char *file, const char *active, const char *patterns) {
FiltersFromPattern(active, patterns, chooser); FiltersFromPattern(active, patterns, chooser);
if(chooser.run() == Gtk::RESPONSE_OK) { if(chooser.run() == Gtk::RESPONSE_OK) {
CnfFreezeString(chooser.get_current_folder().c_str(), "FileChooserPath"); CnfFreezeString(chooser.get_current_folder(), "FileChooserPath");
strcpy(file, chooser.get_filename().c_str()); file = chooser.get_filename();
return true; return true;
} else { } else {
return false; return false;
@ -1134,7 +1132,7 @@ static void ChooserFilterChanged(Gtk::FileChooserDialog *chooser)
} }
} }
bool GetSaveFile(char *file, const char *active, const char *patterns) { bool GetSaveFile(std::string &file, const char *active, const char *patterns) {
Gtk::FileChooserDialog chooser(*GW, "SolveSpace - Save File", Gtk::FileChooserDialog chooser(*GW, "SolveSpace - Save File",
Gtk::FILE_CHOOSER_ACTION_SAVE); Gtk::FILE_CHOOSER_ACTION_SAVE);
chooser.set_do_overwrite_confirmation(true); chooser.set_do_overwrite_confirmation(true);
@ -1153,7 +1151,7 @@ bool GetSaveFile(char *file, const char *active, const char *patterns) {
if(chooser.run() == Gtk::RESPONSE_OK) { if(chooser.run() == Gtk::RESPONSE_OK) {
CnfFreezeString(chooser.get_current_folder(), "FileChooserPath"); CnfFreezeString(chooser.get_current_folder(), "FileChooserPath");
strcpy(file, chooser.get_filename().c_str()); file = chooser.get_filename();
return true; return true;
} else { } else {
return false; return false;
@ -1415,15 +1413,14 @@ void LoadAllFontFiles(void) {
FcFontSet *fs = FcFontList(0, pat, os); FcFontSet *fs = FcFontList(0, pat, os);
for(int i = 0; i < fs->nfont; i++) { for(int i = 0; i < fs->nfont; i++) {
FcChar8 *filename = FcPatternFormat(fs->fonts[i], (const FcChar8*) "%{file}"); FcChar8 *filenameFC = FcPatternFormat(fs->fonts[i], (const FcChar8*) "%{file}");
Glib::ustring ufilename = (char*) filename; std::string filename = (char*) filenameFC;
if(ufilename.length() > 4 && if(FilenameHasExtension(filename, ".ttf")) {
ufilename.substr(ufilename.length() - 4, 4).lowercase() == ".ttf") {
TtfFont tf = {}; TtfFont tf = {};
strcpy(tf.fontFile, (char*) filename); tf.fontFile = filename;
SS.fonts.l.Add(&tf); SS.fonts.l.Add(&tf);
} }
FcStrFree(filename); FcStrFree(filenameFC);
} }
FcFontSetDestroy(fs); FcFontSetDestroy(fs);

View File

@ -189,8 +189,8 @@ public:
enum { REMAP_PRIME = 19477 }; enum { REMAP_PRIME = 19477 };
int remapCache[REMAP_PRIME]; int remapCache[REMAP_PRIME];
char impFile[MAX_PATH]; std::string impFile;
char impFileRel[MAX_PATH]; std::string impFileRel;
SMesh impMesh; SMesh impMesh;
SShell impShell; SShell impShell;
EntityList impEntity; EntityList impEntity;

View File

@ -9,6 +9,8 @@
SolveSpaceUI SolveSpace::SS = {}; SolveSpaceUI SolveSpace::SS = {};
Sketch SolveSpace::SK = {}; Sketch SolveSpace::SK = {};
std::string SolveSpace::RecentFile[MAX_RECENT] = {};
void SolveSpaceUI::Init() { void SolveSpaceUI::Init() {
SS.tangentArcRadius = 10.0; SS.tangentArcRadius = 10.0;
@ -84,10 +86,7 @@ void SolveSpaceUI::Init() {
showToolbar = CnfThawBool(true, "ShowToolbar"); showToolbar = CnfThawBool(true, "ShowToolbar");
// Recent files menus // Recent files menus
for(i = 0; i < MAX_RECENT; i++) { for(i = 0; i < MAX_RECENT; i++) {
char name[100]; RecentFile[i] = CnfThawString("", "RecentFile_" + std::to_string(i));
sprintf(name, "RecentFile_%d", i);
strncpy(RecentFile[i], CnfThawString("", name).c_str(), MAX_PATH);
} }
RefreshRecentMenus(); RefreshRecentMenus();
// Autosave timer // Autosave timer
@ -103,12 +102,10 @@ void SolveSpaceUI::Init() {
AfterNewFile(); AfterNewFile();
} }
bool SolveSpaceUI::LoadAutosaveFor(const char *filename) { bool SolveSpaceUI::LoadAutosaveFor(const std::string &filename) {
char autosaveFile[MAX_PATH]; std::string autosaveFile = filename + AUTOSAVE_SUFFIX;
strcpy(autosaveFile, filename);
strcat(autosaveFile, AUTOSAVE_SUFFIX);
FILE *f = fopen(autosaveFile, "r"); FILE *f = fopen(autosaveFile.c_str(), "r");
if(!f) if(!f)
return false; return false;
fclose(f); fclose(f);
@ -121,13 +118,13 @@ bool SolveSpaceUI::LoadAutosaveFor(const char *filename) {
return false; return false;
} }
bool SolveSpaceUI::OpenFile(const char *filename) { bool SolveSpaceUI::OpenFile(const std::string &filename) {
bool autosaveLoaded = LoadAutosaveFor(filename); bool autosaveLoaded = LoadAutosaveFor(filename);
bool success = autosaveLoaded || LoadFromFile(filename); bool success = autosaveLoaded || LoadFromFile(filename);
if(success) { if(success) {
RemoveAutosave(); RemoveAutosave();
AddToRecentList(filename); AddToRecentList(filename);
strcpy(saveFile, filename); saveFile = filename;
} else { } else {
NewFile(); NewFile();
} }
@ -137,18 +134,12 @@ bool SolveSpaceUI::OpenFile(const char *filename) {
} }
void SolveSpaceUI::Exit(void) { void SolveSpaceUI::Exit(void) {
int i;
char name[100];
// Recent files // Recent files
for(i = 0; i < MAX_RECENT; i++) { for(int i = 0; i < MAX_RECENT; i++)
sprintf(name, "RecentFile_%d", i); CnfFreezeString(RecentFile[i], "RecentFile_" + std::to_string(i));
CnfFreezeString(RecentFile[i], name);
}
// Model colors // Model colors
for(i = 0; i < MODEL_COLORS; i++) { for(int i = 0; i < MODEL_COLORS; i++)
sprintf(name, "ModelColor_%d", i); CnfFreezeColor(modelColor[i], "ModelColor_" + std::to_string(i));
CnfFreezeColor(modelColor[i], name);
}
// Light intensities // Light intensities
CnfFreezeFloat((float)lightIntensity[0], "LightIntensity_0"); CnfFreezeFloat((float)lightIntensity[0], "LightIntensity_0");
CnfFreezeFloat((float)lightIntensity[1], "LightIntensity_1"); CnfFreezeFloat((float)lightIntensity[1], "LightIntensity_1");
@ -339,34 +330,33 @@ void SolveSpaceUI::AfterNewFile(void) {
UpdateWindowTitle(); UpdateWindowTitle();
} }
void SolveSpaceUI::RemoveFromRecentList(const char *file) { void SolveSpaceUI::RemoveFromRecentList(const std::string &filename) {
int src, dest; int src, dest;
dest = 0; dest = 0;
for(src = 0; src < MAX_RECENT; src++) { for(src = 0; src < MAX_RECENT; src++) {
if(strcmp(file, RecentFile[src]) != 0) { if(filename != RecentFile[src]) {
if(src != dest) strcpy(RecentFile[dest], RecentFile[src]); if(src != dest) RecentFile[dest] = RecentFile[src];
dest++; dest++;
} }
} }
while(dest < MAX_RECENT) strcpy(RecentFile[dest++], ""); while(dest < MAX_RECENT) RecentFile[dest++].clear();
RefreshRecentMenus(); RefreshRecentMenus();
} }
void SolveSpaceUI::AddToRecentList(const char *file) { void SolveSpaceUI::AddToRecentList(const std::string &filename) {
RemoveFromRecentList(file); RemoveFromRecentList(filename);
int src; int src;
for(src = MAX_RECENT - 2; src >= 0; src--) { for(src = MAX_RECENT - 2; src >= 0; src--) {
strcpy(RecentFile[src+1], RecentFile[src]); RecentFile[src+1] = RecentFile[src];
} }
strcpy(RecentFile[0], file); RecentFile[0] = filename;
RefreshRecentMenus(); RefreshRecentMenus();
} }
bool SolveSpaceUI::GetFilenameAndSave(bool saveAs) { bool SolveSpaceUI::GetFilenameAndSave(bool saveAs) {
char prevSaveFile[MAX_PATH]; std::string prevSaveFile = saveFile;
strcpy(prevSaveFile, saveFile);
if(saveAs || strlen(saveFile)==0) { if(saveAs || saveFile.empty()) {
if(!GetSaveFile(saveFile, SLVS_EXT, SLVS_PATTERN)) return false; if(!GetSaveFile(saveFile, SLVS_EXT, SLVS_PATTERN)) return false;
// need to get new filename directly into saveFile, since that // need to get new filename directly into saveFile, since that
// determines impFileRel path // determines impFileRel path
@ -379,7 +369,7 @@ bool SolveSpaceUI::GetFilenameAndSave(bool saveAs) {
return true; return true;
} else { } else {
// don't store an invalid save filename // don't store an invalid save filename
strcpy(saveFile, prevSaveFile); saveFile = prevSaveFile;
return false; return false;
} }
} }
@ -388,22 +378,16 @@ bool SolveSpaceUI::Autosave()
{ {
SetAutosaveTimerFor(autosaveInterval); SetAutosaveTimerFor(autosaveInterval);
if (strlen(saveFile) != 0 && unsaved) { if(!saveFile.empty() && unsaved)
char autosaveFile[MAX_PATH]; return SaveToFile(saveFile + AUTOSAVE_SUFFIX);
strcpy(autosaveFile, saveFile);
strcat(autosaveFile, AUTOSAVE_SUFFIX);
return SaveToFile(autosaveFile);
}
return false; return false;
} }
void SolveSpaceUI::RemoveAutosave() void SolveSpaceUI::RemoveAutosave()
{ {
char autosaveFile[MAX_PATH]; std::string autosaveFile = saveFile + AUTOSAVE_SUFFIX;
strcpy(autosaveFile, saveFile); remove(autosaveFile.c_str());
strcat(autosaveFile, AUTOSAVE_SUFFIX);
remove(autosaveFile);
} }
bool SolveSpaceUI::OkayToStartNewFile(void) { bool SolveSpaceUI::OkayToStartNewFile(void) {
@ -424,14 +408,10 @@ bool SolveSpaceUI::OkayToStartNewFile(void) {
} }
void SolveSpaceUI::UpdateWindowTitle(void) { void SolveSpaceUI::UpdateWindowTitle(void) {
if(strlen(saveFile) == 0) {
SetCurrentFilename(NULL);
} else {
SetCurrentFilename(saveFile); SetCurrentFilename(saveFile);
}
} }
static std::string Extname(std::string filename) { static std::string Extension(const std::string &filename) {
int dot = filename.rfind('.'); int dot = filename.rfind('.');
if(dot >= 0) if(dot >= 0)
return filename.substr(dot + 1, filename.length()); return filename.substr(dot + 1, filename.length());
@ -442,8 +422,7 @@ void SolveSpaceUI::MenuFile(int id) {
if(id >= RECENT_OPEN && id < (RECENT_OPEN+MAX_RECENT)) { if(id >= RECENT_OPEN && id < (RECENT_OPEN+MAX_RECENT)) {
if(!SS.OkayToStartNewFile()) return; if(!SS.OkayToStartNewFile()) return;
char newFile[MAX_PATH]; std::string newFile = RecentFile[id - RECENT_OPEN];
strcpy(newFile, RecentFile[id-RECENT_OPEN]);
RemoveFromRecentList(newFile); RemoveFromRecentList(newFile);
SS.OpenFile(newFile); SS.OpenFile(newFile);
return; return;
@ -453,7 +432,7 @@ void SolveSpaceUI::MenuFile(int id) {
case GraphicsWindow::MNU_NEW: case GraphicsWindow::MNU_NEW:
if(!SS.OkayToStartNewFile()) break; if(!SS.OkayToStartNewFile()) break;
strcpy(SS.saveFile, ""); SS.saveFile = "";
SS.NewFile(); SS.NewFile();
SS.AfterNewFile(); SS.AfterNewFile();
break; break;
@ -461,7 +440,7 @@ void SolveSpaceUI::MenuFile(int id) {
case GraphicsWindow::MNU_OPEN: { case GraphicsWindow::MNU_OPEN: {
if(!SS.OkayToStartNewFile()) break; if(!SS.OkayToStartNewFile()) break;
char newFile[MAX_PATH] = ""; std::string newFile;
if(GetOpenFile(newFile, SLVS_EXT, SLVS_PATTERN)) { if(GetOpenFile(newFile, SLVS_EXT, SLVS_PATTERN)) {
SS.OpenFile(newFile); SS.OpenFile(newFile);
} }
@ -477,22 +456,21 @@ void SolveSpaceUI::MenuFile(int id) {
break; break;
case GraphicsWindow::MNU_EXPORT_PNG: { case GraphicsWindow::MNU_EXPORT_PNG: {
char exportFile[MAX_PATH] = ""; std::string exportFile;
if(!GetSaveFile(exportFile, PNG_EXT, PNG_PATTERN)) break; if(!GetSaveFile(exportFile, PNG_EXT, PNG_PATTERN)) break;
SS.ExportAsPngTo(exportFile); SS.ExportAsPngTo(exportFile);
break; break;
} }
case GraphicsWindow::MNU_EXPORT_VIEW: { case GraphicsWindow::MNU_EXPORT_VIEW: {
char exportFile[MAX_PATH] = "", exportExt[10] = VEC_EXT; std::string exportFile = CnfThawString("", "2DExportFormat");
strncpy(exportFile, CnfThawString("", "2DExportFormat").c_str(), MAX_PATH); if(!GetSaveFile(exportFile, VEC_EXT, VEC_PATTERN)) break;
if(!GetSaveFile(exportFile, exportExt, VEC_PATTERN)) break; CnfFreezeString(Extension(exportFile), "2DExportFormat");
CnfFreezeString(Extname(exportFile), "2DExportFormat");
// If the user is exporting something where it would be // If the user is exporting something where it would be
// inappropriate to include the constraints, then warn. // inappropriate to include the constraints, then warn.
if(SS.GW.showConstraints && if(SS.GW.showConstraints &&
(StringEndsIn(exportFile, ".txt") || (FilenameHasExtension(exportFile, ".txt") ||
fabs(SS.exportOffset) > LENGTH_EPS)) fabs(SS.exportOffset) > LENGTH_EPS))
{ {
Message("Constraints are currently shown, and will be exported " Message("Constraints are currently shown, and will be exported "
@ -506,28 +484,28 @@ void SolveSpaceUI::MenuFile(int id) {
} }
case GraphicsWindow::MNU_EXPORT_WIREFRAME: { case GraphicsWindow::MNU_EXPORT_WIREFRAME: {
char exportFile[MAX_PATH] = ""; std::string exportFile;
if(!GetSaveFile(exportFile, V3D_EXT, V3D_PATTERN)) break; if(!GetSaveFile(exportFile, V3D_EXT, V3D_PATTERN)) break;
SS.ExportViewOrWireframeTo(exportFile, true); SS.ExportViewOrWireframeTo(exportFile, true);
break; break;
} }
case GraphicsWindow::MNU_EXPORT_SECTION: { case GraphicsWindow::MNU_EXPORT_SECTION: {
char exportFile[MAX_PATH] = ""; std::string exportFile;
if(!GetSaveFile(exportFile, VEC_EXT, VEC_PATTERN)) break; if(!GetSaveFile(exportFile, VEC_EXT, VEC_PATTERN)) break;
SS.ExportSectionTo(exportFile); SS.ExportSectionTo(exportFile);
break; break;
} }
case GraphicsWindow::MNU_EXPORT_MESH: { case GraphicsWindow::MNU_EXPORT_MESH: {
char exportFile[MAX_PATH] = ""; std::string exportFile;
if(!GetSaveFile(exportFile, MESH_EXT, MESH_PATTERN)) break; if(!GetSaveFile(exportFile, MESH_EXT, MESH_PATTERN)) break;
SS.ExportMeshTo(exportFile); SS.ExportMeshTo(exportFile);
break; break;
} }
case GraphicsWindow::MNU_EXPORT_SURFACES: { case GraphicsWindow::MNU_EXPORT_SURFACES: {
char exportFile[MAX_PATH] = ""; std::string exportFile;
if(!GetSaveFile(exportFile, SRF_EXT, SRF_PATTERN)) break; if(!GetSaveFile(exportFile, SRF_EXT, SRF_PATTERN)) break;
StepFileWriter sfw = {}; StepFileWriter sfw = {};
sfw.ExportSurfacesTo(exportFile); sfw.ExportSurfacesTo(exportFile);
@ -747,9 +725,9 @@ void SolveSpaceUI::MenuAnalyze(int id) {
break; break;
case GraphicsWindow::MNU_STOP_TRACING: { case GraphicsWindow::MNU_STOP_TRACING: {
char exportFile[MAX_PATH] = ""; std::string exportFile;
if(GetSaveFile(exportFile, CSV_EXT, CSV_PATTERN)) { if(GetSaveFile(exportFile, CSV_EXT, CSV_PATTERN)) {
FILE *f = fopen(exportFile, "wb"); FILE *f = fopen(exportFile.c_str(), "wb");
if(f) { if(f) {
int i; int i;
SContour *sc = &(SS.traced.path); SContour *sc = &(SS.traced.path);
@ -761,7 +739,7 @@ void SolveSpaceUI::MenuAnalyze(int id) {
} }
fclose(f); fclose(f);
} else { } else {
Error("Couldn't write to '%s'", exportFile); Error("Couldn't write to '%s'", exportFile.c_str());
} }
} }
// Clear the trace, and stop tracing // Clear the trace, and stop tracing

View File

@ -114,16 +114,12 @@ class ExprVector;
class ExprQuaternion; class ExprQuaternion;
class RgbaColor; class RgbaColor;
#ifndef MAX_PATH
# define MAX_PATH PATH_MAX
#endif
//================ //================
// From the platform-specific code. // From the platform-specific code.
#define MAX_RECENT 8 #define MAX_RECENT 8
#define RECENT_OPEN (0xf000) #define RECENT_OPEN (0xf000)
#define RECENT_IMPORT (0xf100) #define RECENT_IMPORT (0xf100)
extern char RecentFile[MAX_RECENT][MAX_PATH]; extern std::string RecentFile[MAX_RECENT];
void RefreshRecentMenus(void); void RefreshRecentMenus(void);
#define SAVE_YES (1) #define SAVE_YES (1)
@ -196,9 +192,9 @@ int LoadAutosaveYesNo(void);
// Comma-separated value, like a spreadsheet would use // Comma-separated value, like a spreadsheet would use
#define CSV_PATTERN PAT1("CSV File", "csv") ENDPAT #define CSV_PATTERN PAT1("CSV File", "csv") ENDPAT
#define CSV_EXT "csv" #define CSV_EXT "csv"
bool GetSaveFile(char *file, const char *defExtension, const char *selPattern); bool GetSaveFile(std::string &filename, const char *defExtension, const char *selPattern);
bool GetOpenFile(char *file, const char *defExtension, const char *selPattern); bool GetOpenFile(std::string &filename, const char *defExtension, const char *selPattern);
void GetAbsoluteFilename(char *file); std::string GetAbsoluteFilename(const std::string &filename);
void LoadAllFontFiles(void); void LoadAllFontFiles(void);
void OpenWebsite(const char *url); void OpenWebsite(const char *url);
@ -239,7 +235,7 @@ void dbp(const char *str, ...);
dbp("tri: (%.3f %.3f %.3f) (%.3f %.3f %.3f) (%.3f %.3f %.3f)", \ dbp("tri: (%.3f %.3f %.3f) (%.3f %.3f %.3f) (%.3f %.3f %.3f)", \
CO((tri).a), CO((tri).b), CO((tri).c)) CO((tri).a), CO((tri).b), CO((tri).c))
void SetCurrentFilename(const char *filename); void SetCurrentFilename(const std::string &filename);
void SetMousePointerToHand(bool yes); void SetMousePointerToHand(bool yes);
void DoMessageBox(const char *str, int rows, int cols, bool error); void DoMessageBox(const char *str, int rows, int cols, bool error);
void SetTimerFor(int milliseconds); void SetTimerFor(int milliseconds);
@ -334,11 +330,11 @@ void MakeMatrix(double *mat, double a11, double a12, double a13, double a14,
double a21, double a22, double a23, double a24, double a21, double a22, double a23, double a24,
double a31, double a32, double a33, double a34, double a31, double a32, double a33, double a34,
double a41, double a42, double a43, double a44); double a41, double a42, double a43, double a44);
void MakePathRelative(const char *base, char *path); std::string MakePathRelative(const std::string &base, const std::string &path);
void MakePathAbsolute(const char *base, char *path); std::string MakePathAbsolute(const std::string &base, const std::string &path);
bool MakeAcceleratorLabel(int accel, char *out); bool MakeAcceleratorLabel(int accel, char *out);
bool StringAllPrintable(const char *str); bool StringAllPrintable(const char *str);
bool StringEndsIn(const char *str, const char *ending); bool FilenameHasExtension(const std::string &str, const char *ext);
void Message(const char *str, ...); void Message(const char *str, ...);
void Error(const char *str, ...); void Error(const char *str, ...);
void CnfFreezeBool(bool v, const std::string &name); void CnfFreezeBool(bool v, const std::string &name);
@ -448,7 +444,7 @@ public:
int x, y; int x, y;
} IntPoint; } IntPoint;
char fontFile[MAX_PATH]; std::string fontFile;
NameStr name; NameStr name;
bool loaded; bool loaded;
@ -484,7 +480,7 @@ public:
void LoadGlyph(int index); void LoadGlyph(int index);
bool LoadFontFromFile(bool nameOnly); bool LoadFontFromFile(bool nameOnly);
const char *FontFileBaseName(void); std::string FontFileBaseName(void);
void Flush(void); void Flush(void);
void Handle(int *dx, int x, int y, bool onCurve); void Handle(int *dx, int x, int y, bool onCurve);
@ -504,13 +500,13 @@ public:
void LoadAll(void); void LoadAll(void);
void PlotString(char *font, char *str, double spacing, void PlotString(const std::string &font, char *str, double spacing,
SBezierList *sbl, Vector origin, Vector u, Vector v); SBezierList *sbl, Vector origin, Vector u, Vector v);
}; };
class StepFileWriter { class StepFileWriter {
public: public:
void ExportSurfacesTo(char *filename); void ExportSurfacesTo(const std::string &filename);
void WriteHeader(void); void WriteHeader(void);
void WriteProductHeader(void); void WriteProductHeader(void);
int ExportCurve(SBezier *sb); int ExportCurve(SBezier *sb);
@ -536,7 +532,7 @@ public:
static double MmToPts(double mm); static double MmToPts(double mm);
static VectorFileWriter *ForFile(const char *file); static VectorFileWriter *ForFile(const std::string &filename);
void Output(SBezierLoopSetSet *sblss, SMesh *sm); void Output(SBezierLoopSetSet *sblss, SMesh *sm);
@ -791,16 +787,16 @@ public:
// The platform-dependent code calls this before entering the msg loop // The platform-dependent code calls this before entering the msg loop
void Init(void); void Init(void);
bool OpenFile(const char *filename); bool OpenFile(const std::string &filename);
void Exit(void); void Exit(void);
// File load/save routines, including the additional files that get // File load/save routines, including the additional files that get
// loaded when we have import groups. // loaded when we have import groups.
FILE *fh; FILE *fh;
void AfterNewFile(void); void AfterNewFile(void);
static void RemoveFromRecentList(const char *file); static void RemoveFromRecentList(const std::string &filename);
static void AddToRecentList(const char *file); static void AddToRecentList(const std::string &filename);
char saveFile[MAX_PATH]; std::string saveFile;
bool fileLoadError; bool fileLoadError;
bool unsaved; bool unsaved;
typedef struct { typedef struct {
@ -829,20 +825,20 @@ public:
void UpdateWindowTitle(void); void UpdateWindowTitle(void);
void ClearExisting(void); void ClearExisting(void);
void NewFile(void); void NewFile(void);
bool SaveToFile(const char *filename); bool SaveToFile(const std::string &filename);
bool LoadAutosaveFor(const char *filename); bool LoadAutosaveFor(const std::string &filename);
bool LoadFromFile(const char *filename); bool LoadFromFile(const std::string &filename);
bool LoadEntitiesFromFile(const char *filename, EntityList *le, bool LoadEntitiesFromFile(const std::string &filename, EntityList *le,
SMesh *m, SShell *sh); SMesh *m, SShell *sh);
void ReloadAllImported(void); void ReloadAllImported(void);
// And the various export options // And the various export options
void ExportAsPngTo(const char *file); void ExportAsPngTo(const std::string &filename);
void ExportMeshTo(const char *file); void ExportMeshTo(const std::string &filename);
void ExportMeshAsStlTo(FILE *f, SMesh *sm); void ExportMeshAsStlTo(FILE *f, SMesh *sm);
void ExportMeshAsObjTo(FILE *f, SMesh *sm); void ExportMeshAsObjTo(FILE *f, SMesh *sm);
void ExportMeshAsThreeJsTo(FILE *f, const char * filename, SMesh *sm, SEdgeList *sel); void ExportMeshAsThreeJsTo(FILE *f, const std::string &filename, SMesh *sm, SEdgeList *sel);
void ExportViewOrWireframeTo(const char *file, bool wireframe); void ExportViewOrWireframeTo(const std::string &filename, bool wireframe);
void ExportSectionTo(const char *file); void ExportSectionTo(const std::string &filename);
void ExportWireframeCurves(SEdgeList *sel, SBezierList *sbl, void ExportWireframeCurves(SEdgeList *sel, SBezierList *sbl,
VectorFileWriter *out); VectorFileWriter *out);
void ExportLinesAndMesh(SEdgeList *sel, SBezierList *sbl, SMesh *sm, void ExportLinesAndMesh(SEdgeList *sel, SBezierList *sbl, SMesh *sm,

View File

@ -374,9 +374,9 @@ void TextWindow::ScreenBackgroundImage(int link, uint32_t v) {
png_struct *png_ptr = NULL; png_struct *png_ptr = NULL;
png_info *info_ptr = NULL; png_info *info_ptr = NULL;
char importFile[MAX_PATH] = ""; std::string importFile;
if(!GetOpenFile(importFile, PNG_EXT, PNG_PATTERN)) goto err; if(!GetOpenFile(importFile, PNG_EXT, PNG_PATTERN)) goto err;
f = fopen(importFile, "rb"); f = fopen(importFile.c_str(), "rb");
if(!f) goto err; if(!f) goto err;
uint8_t header[8]; uint8_t header[8];

View File

@ -331,7 +331,7 @@ void TextWindow::ShowGroupInfo(void) {
} }
} else if(g->type == Group::IMPORTED) { } else if(g->type == Group::IMPORTED) {
Printf(true, " %Ftimport geometry from file%E"); Printf(true, " %Ftimport geometry from file%E");
Printf(false, "%Ba '%s'", g->impFileRel); Printf(false, "%Ba '%s'", g->impFileRel.c_str());
Printf(false, "%Bd %Ftscaled by%E %# %Fl%Ll%f%D[change]%E", Printf(false, "%Bd %Ftscaled by%E %# %Fl%Ll%f%D[change]%E",
g->scale, g->scale,
&TextWindow::ScreenChangeGroupScale, g->h.v); &TextWindow::ScreenChangeGroupScale, g->h.v);

View File

@ -26,7 +26,7 @@ void TtfFontList::LoadAll(void) {
loaded = true; loaded = true;
} }
void TtfFontList::PlotString(char *font, char *str, double spacing, void TtfFontList::PlotString(const std::string &font, char *str, double spacing,
SBezierList *sbl, SBezierList *sbl,
Vector origin, Vector u, Vector v) Vector origin, Vector u, Vector v)
{ {
@ -35,7 +35,7 @@ void TtfFontList::PlotString(char *font, char *str, double spacing,
int i; int i;
for(i = 0; i < l.n; i++) { for(i = 0; i < l.n; i++) {
TtfFont *tf = &(l.elem[i]); TtfFont *tf = &(l.elem[i]);
if(strcmp(tf->FontFileBaseName(), font)==0) { if(tf->FontFileBaseName() == font) {
tf->LoadFontFromFile(false); tf->LoadFontFromFile(false);
tf->PlotString(str, spacing, sbl, origin, u, v); tf->PlotString(str, spacing, sbl, origin, u, v);
return; return;
@ -228,12 +228,15 @@ void TtfFont::LoadGlyph(int index) {
// Return the basename of our font filename; that's how the requests and // Return the basename of our font filename; that's how the requests and
// entities that reference us will store it. // entities that reference us will store it.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
const char *TtfFont::FontFileBaseName(void) { std::string TtfFont::FontFileBaseName(void) {
char *sb = strrchr(fontFile, '\\'); size_t pos;
char *sf = strrchr(fontFile, '/'); pos = fontFile.rfind('/');
char *s = sf ? sf : sb; if(pos != std::string::npos)
if(!s) return ""; return fontFile.erase(0, pos);
return s + 1; pos = fontFile.rfind('\\');
if(pos != std::string::npos)
return fontFile.erase(0, pos);
return "";
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -246,7 +249,7 @@ bool TtfFont::LoadFontFromFile(bool nameOnly) {
int i; int i;
fh = fopen(fontFile, "rb"); fh = fopen(fontFile.c_str(), "rb");
if(!fh) { if(!fh) {
return false; return false;
} }
@ -580,7 +583,7 @@ bool TtfFont::LoadFontFromFile(bool nameOnly) {
LoadGlyph(i); LoadGlyph(i);
} }
} catch (const char *s) { } catch (const char *s) {
dbp("ttf: file %s failed: '%s'", fontFile, s); dbp("ttf: file %s failed: '%s'", fontFile.c_str(), s);
fclose(fh); fclose(fh);
return false; return false;
} }

View File

@ -30,11 +30,18 @@ void dbp(const char *str, ...)
fputc('\n', stderr); fputc('\n', stderr);
} }
void GetAbsoluteFilename(char *file) std::string GetAbsoluteFilename(const std::string &filename)
{ {
char expanded[MAX_PATH]; // We rely on the POSIX.1-2008 version of realpath that allocates
realpath(file, expanded); // storage for itself; the POSIX.1-2001 version is broken by design.
strcpy(file, expanded); char *expanded = realpath(filename.c_str(), NULL);
if(expanded) {
std::string result(expanded);
free(expanded);
return result;
} else {
return filename;
}
} }
int64_t GetUnixTime(void) int64_t GetUnixTime(void)

View File

@ -6,45 +6,46 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "solvespace.h" #include "solvespace.h"
void SolveSpace::MakePathRelative(const char *basep, char *pathp) std::string SolveSpace::MakePathRelative(const std::string &basep, const std::string &pathp)
{ {
int i; int i;
const char *p; const char *p;
char base[MAX_PATH], path[MAX_PATH], out[MAX_PATH]; std::string base, path;
// Convert everything to lowercase // Convert everything to lowercase
p = basep; // FIXME: This is not generally safe to do on Linux/FreeBSD
for(i = 0; *p; p++) { // FIXME: tolower will try to respect locale on POSIX. This is, obviously, broken
base[i++] = (char)tolower(*p); p = &basep[0];
} for(i = 0; *p; p++)
base[i++] = '\0'; base += (char)tolower(*p);
p = pathp;
for(i = 0; *p; p++) { p = &pathp[0];
path[i++] = (char)tolower(*p); for(i = 0; *p; p++)
} path += (char)tolower(*p);
path[i++] = '\0';
// Find the length of the common prefix // Find the length of the common prefix
int com; int com;
for(com = 0; base[com] && path[com]; com++) { for(com = 0; com < base.length() && com < path.length(); com++) {
if(base[com] != path[com]) break; if(base[com] != path[com]) break;
} }
if(!(base[com] && path[com])) return; // weird, prefix is entire string if(com == base.length() || com == path.length())
if(com == 0) return; // maybe on different drive letters? return pathp; // weird, prefix is entire string
if(com == 0)
return pathp; // maybe on different drive letters?
// Align the common prefix to the nearest slash; otherwise would break // Align the common prefix to the nearest slash; otherwise would break
// on subdirectories or filenames that shared a prefix. // on subdirectories or filenames that shared a prefix.
while(com >= 1 && base[com-1] != '/' && base[com-1] != '\\') { while(com >= 1 && base[com-1] != '/' && base[com-1] != '\\')
com--; com--;
} if(com == 0) return pathp;
if(com == 0) return;
int sections = 0; int sections = 0;
int secLen = 0, secStart = 0; int secLen = 0, secStart = 0;
for(i = com; base[i]; i++) { for(i = com; i < base.length(); i++) {
if(base[i] == '/' || base[i] == '\\') { if(base[i] == '/' || base[i] == '\\') {
if(secLen == 2 && memcmp(base+secStart, "..", 2)==0) return; if(secLen == 2 && memcmp(&base[secStart], "..", 2)==0) return pathp;
if(secLen == 1 && memcmp(base+secStart, ".", 1)==0) return; if(secLen == 1 && memcmp(&base[secStart], ".", 1)==0) return pathp;
sections++; sections++;
secLen = 0; secLen = 0;
@ -56,32 +57,28 @@ void SolveSpace::MakePathRelative(const char *basep, char *pathp)
// For every directory in the prefix of the base, we must go down a // For every directory in the prefix of the base, we must go down a
// directory in the relative path name // directory in the relative path name
strcpy(out, ""); std::string out;
for(i = 0; i < sections; i++) { for(i = 0; i < sections; i++) {
strcat(out, "../"); out += "../";
} }
// comparison is case-insensitive, but output preserves input case // comparison is case-insensitive, but output preserves input case
strcat(out, pathp+com); out += pathp.substr(com);
return out;
strcpy(pathp, out);
} }
void SolveSpace::MakePathAbsolute(const char *basep, char *pathp) { std::string SolveSpace::MakePathAbsolute(const std::string &basep, const std::string &pathp) {
char out[MAX_PATH]; std::string out = basep;
strcpy(out, basep);
// Chop off the filename // Chop off the filename
int i; int i;
for(i = (int)strlen(out) - 1; i >= 0; i--) { for(i = (int)out.length() - 1; i >= 0; i--) {
if(out[i] == '\\' || out[i] == '/') break; if(out[i] == '\\' || out[i] == '/') break;
} }
if(i < 0) return; // base is not an absolute path, or something? if(i < 0) return pathp; // base is not an absolute path, or something?
out[i+1] = '\0'; out.resize(i + 1);
strcat(out, pathp); out += pathp;
GetAbsoluteFilename(out); return GetAbsoluteFilename(out);
strcpy(pathp, out);
} }
bool SolveSpace::StringAllPrintable(const char *str) bool SolveSpace::StringAllPrintable(const char *str)
@ -95,14 +92,14 @@ bool SolveSpace::StringAllPrintable(const char *str)
return true; return true;
} }
bool SolveSpace::StringEndsIn(const char *str, const char *ending) bool SolveSpace::FilenameHasExtension(const std::string &str, const char *ext)
{ {
int i, ls = (int)strlen(str), le = (int)strlen(ending); int i, ls = str.length(), le = strlen(ext);
if(ls < le) return false; if(ls < le) return false;
for(i = 0; i < le; i++) { for(i = 0; i < le; i++) {
if(tolower(ending[le-i-1]) != tolower(str[ls-i-1])) { if(tolower(ext[le-i-1]) != tolower(str[ls-i-1])) {
return false; return false;
} }
} }

View File

@ -39,7 +39,6 @@ static struct {
int x, y; int x, y;
} LastMousePos; } LastMousePos;
char SolveSpace::RecentFile[MAX_RECENT][MAX_PATH];
HMENU SubMenus[100]; HMENU SubMenus[100];
HMENU RecentOpenMenu, RecentImportMenu; HMENU RecentOpenMenu, RecentImportMenu;
@ -376,7 +375,8 @@ std::string SolveSpace::CnfThawString(const std::string &val, const std::string
return val; return val;
} }
std::string newval(len, '\0'); std::string newval;
newval.resize(len - 1);
if(RegQueryValueEx(SolveSpace, &name[0], NULL, if(RegQueryValueEx(SolveSpace, &name[0], NULL,
NULL, (BYTE*) &newval[0], &len) != ERROR_SUCCESS) { NULL, (BYTE*) &newval[0], &len) != ERROR_SUCCESS) {
RegCloseKey(SolveSpace); RegCloseKey(SolveSpace);
@ -412,10 +412,9 @@ static void ThawWindowPos(HWND hwnd, const std::string &name)
ShowWindow(hwnd, SW_MAXIMIZE); ShowWindow(hwnd, SW_MAXIMIZE);
} }
void SolveSpace::SetCurrentFilename(const char *filename) { void SolveSpace::SetCurrentFilename(const std::string &filename) {
if(filename) { if(!filename.empty()) {
std::string title = std::string("SolveSpace - ") + filename; SetWindowText(GraphicsWnd, ("SolveSpace - " + filename).c_str());
SetWindowText(GraphicsWnd, title.c_str());
} else { } else {
SetWindowText(GraphicsWnd, "SolveSpace - (not yet saved)"); SetWindowText(GraphicsWnd, "SolveSpace - (not yet saved)");
} }
@ -959,17 +958,24 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Common dialog routines, to open or save a file. // Common dialog routines, to open or save a file.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool SolveSpace::GetOpenFile(char *file, const char *defExtension, const char *selPattern) bool SolveSpace::GetOpenFile(std::string &filename,
const char *defExtension, const char *selPattern)
{ {
OPENFILENAME ofn = {}; // UNC paths may be arbitrarily long.
// Unfortunately, the Get*FileName API does not provide any way to use it
// except with a preallocated buffer of fixed size, so we use something
// reasonably large.
char filenameC[0xFFFF] = {};
strncpy(filenameC, filename.c_str(), sizeof(filenameC) - 1);
OPENFILENAME ofn = {};
ofn.lStructSize = sizeof(ofn); ofn.lStructSize = sizeof(ofn);
ofn.hInstance = Instance; ofn.hInstance = Instance;
ofn.hwndOwner = GraphicsWnd; ofn.hwndOwner = GraphicsWnd;
ofn.lpstrFilter = selPattern; ofn.lpstrFilter = selPattern;
ofn.lpstrDefExt = defExtension; ofn.lpstrDefExt = defExtension;
ofn.lpstrFile = file; ofn.lpstrFile = filenameC;
ofn.nMaxFile = MAX_PATH; ofn.nMaxFile = sizeof(filenameC);
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
EnableWindow(GraphicsWnd, false); EnableWindow(GraphicsWnd, false);
@ -981,20 +987,25 @@ bool SolveSpace::GetOpenFile(char *file, const char *defExtension, const char *s
EnableWindow(GraphicsWnd, true); EnableWindow(GraphicsWnd, true);
SetForegroundWindow(GraphicsWnd); SetForegroundWindow(GraphicsWnd);
if(r) filename = filenameC;
return r ? true : false; return r ? true : false;
} }
bool SolveSpace::GetSaveFile(char *file, const char *defExtension, const char *selPattern) bool SolveSpace::GetSaveFile(std::string &filename,
const char *defExtension, const char *selPattern)
{ {
OPENFILENAME ofn = {}; // See GetOpenFile
char filenameC[0xFFFF] = {};
strncpy(filenameC, filename.c_str(), sizeof(filenameC) - 1);
OPENFILENAME ofn = {};
ofn.lStructSize = sizeof(ofn); ofn.lStructSize = sizeof(ofn);
ofn.hInstance = Instance; ofn.hInstance = Instance;
ofn.hwndOwner = GraphicsWnd; ofn.hwndOwner = GraphicsWnd;
ofn.lpstrFilter = selPattern; ofn.lpstrFilter = selPattern;
ofn.lpstrDefExt = defExtension; ofn.lpstrDefExt = defExtension;
ofn.lpstrFile = file; ofn.lpstrFile = filenameC;
ofn.nMaxFile = MAX_PATH; ofn.nMaxFile = sizeof(filenameC);
ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
EnableWindow(GraphicsWnd, false); EnableWindow(GraphicsWnd, false);
@ -1006,6 +1017,7 @@ bool SolveSpace::GetSaveFile(char *file, const char *defExtension, const char *s
EnableWindow(GraphicsWnd, true); EnableWindow(GraphicsWnd, true);
SetForegroundWindow(GraphicsWnd); SetForegroundWindow(GraphicsWnd);
if(r) filename = filenameC;
return r ? true : false; return r ? true : false;
} }
@ -1057,22 +1069,15 @@ int SolveSpace::LoadAutosaveYesNo(void)
void SolveSpace::LoadAllFontFiles(void) void SolveSpace::LoadAllFontFiles(void)
{ {
std::string fontsDir(MAX_PATH, '\0');
fontsDir.resize(GetWindowsDirectory(&fontsDir[0], fontsDir.length()));
fontsDir += "\\fonts\\";
WIN32_FIND_DATA wfd; WIN32_FIND_DATA wfd;
char dir[MAX_PATH]; HANDLE h = FindFirstFile((fontsDir + "*.ttf").c_str(), &wfd);
GetWindowsDirectory(dir, MAX_PATH - 30);
strcat(dir, "\\fonts\\*.ttf");
HANDLE h = FindFirstFile(dir, &wfd);
while(h != INVALID_HANDLE_VALUE) { while(h != INVALID_HANDLE_VALUE) {
TtfFont tf = {}; TtfFont tf = {};
tf.fontFile = fontsDir + wfd.cFileName;
char fullPath[MAX_PATH];
GetWindowsDirectory(fullPath, MAX_PATH - (30 + (UINT)strlen(wfd.cFileName)));
strcat(fullPath, "\\fonts\\");
strcat(fullPath, wfd.cFileName);
strcpy(tf.fontFile, fullPath);
SS.fonts.l.Add(&tf); SS.fonts.l.Add(&tf);
if(!FindNextFile(h, &wfd)) break; if(!FindNextFile(h, &wfd)) break;
@ -1122,9 +1127,8 @@ static void DoRecent(HMENU m, int base)
; ;
int i, c = 0; int i, c = 0;
for(i = 0; i < MAX_RECENT; i++) { for(i = 0; i < MAX_RECENT; i++) {
char *s = RecentFile[i]; if(!RecentFile[i].empty()) {
if(*s) { AppendMenu(m, MF_STRING, base + i, RecentFile[i].c_str());
AppendMenu(m, MF_STRING, base+i, s);
c++; c++;
} }
} }
@ -1329,17 +1333,16 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
// A filename may have been specified on the command line; if so, then // A filename may have been specified on the command line; if so, then
// strip any quotation marks, and make it absolute. // strip any quotation marks, and make it absolute.
char file[MAX_PATH] = ""; std::string filename = lpCmdLine;
if(strlen(lpCmdLine)+1 < MAX_PATH) { size_t pos;
char *s = lpCmdLine; pos = filename.find_last_not_of("\"");
while(*s == ' ' || *s == '"') s++; if(pos != std::string::npos)
strcpy(file, s); filename.erase(pos + 1);
s = strrchr(file, '"'); pos = filename.find_first_not_of(" \"");
if(s) *s = '\0'; if(pos != std::string::npos)
} filename.erase(0, pos);
if(*file != '\0') { if(!filename.empty())
GetAbsoluteFilename(file); filename = GetAbsoluteFilename(filename);
}
#ifdef HAVE_SPACEWARE #ifdef HAVE_SPACEWARE
// Initialize the SpaceBall, if present. Test if the driver is running // Initialize the SpaceBall, if present. Test if the driver is running
@ -1357,8 +1360,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
// Call in to the platform-independent code, and let them do their init // Call in to the platform-independent code, and let them do their init
SS.Init(); SS.Init();
if(strcmp(file, "")) if(!filename.empty())
SS.OpenFile(file); SS.OpenFile(filename);
// And now it's the message loop. All calls in to the rest of the code // And now it's the message loop. All calls in to the rest of the code
// will be from the wndprocs. // will be from the wndprocs.

View File

@ -22,11 +22,13 @@ void dbp(const char *str, ...)
OutputDebugString(buf); OutputDebugString(buf);
} }
void GetAbsoluteFilename(char *file) std::string GetAbsoluteFilename(const std::string &in)
{ {
char absoluteFile[MAX_PATH]; std::string out;
GetFullPathName(file, sizeof(absoluteFile), absoluteFile, NULL); DWORD len = GetFullPathName(in.data(), 0, NULL, NULL);
strcpy(file, absoluteFile); out.resize(len - 1);
GetFullPathName(in.c_str(), len, &out[0], NULL);
return out;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------