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

View File

@ -35,7 +35,7 @@ void TextWindow::ScreenSetTtfFont(int link, uint32_t v) {
if(!r) return;
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.ScheduleGenerateAll();
SS.ScheduleShowTW();
@ -178,7 +178,7 @@ void TextWindow::DescribeSelection(void) {
int i;
for(i = 0; i < SS.fonts.l.n; 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",
(i & 1) ? 'd' : 'a',
tf->name.str);

View File

@ -9,7 +9,7 @@
#include "solvespace.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);
gn = gn.WithMagnitude(1);
@ -107,7 +107,7 @@ void SolveSpaceUI::ExportSectionTo(const char *filename) {
bl.Clear();
}
void SolveSpaceUI::ExportViewOrWireframeTo(const char *filename, bool wireframe) {
void SolveSpaceUI::ExportViewOrWireframeTo(const std::string &filename, bool wireframe) {
int i;
SEdgeList edges = {};
SBezierList beziers = {};
@ -389,27 +389,27 @@ double VectorFileWriter::MmToPts(double mm) {
return (mm/25.4)*72;
}
VectorFileWriter *VectorFileWriter::ForFile(const char *filename) {
VectorFileWriter *VectorFileWriter::ForFile(const std::string &filename) {
VectorFileWriter *ret;
if(StringEndsIn(filename, ".dxf")) {
if(FilenameHasExtension(filename, ".dxf")) {
static DxfFileWriter DxfWriter;
ret = &DxfWriter;
} else if(StringEndsIn(filename, ".ps") || StringEndsIn(filename, ".eps")) {
} else if(FilenameHasExtension(filename, ".ps") || FilenameHasExtension(filename, ".eps")) {
static EpsFileWriter EpsWriter;
ret = &EpsWriter;
} else if(StringEndsIn(filename, ".pdf")) {
} else if(FilenameHasExtension(filename, ".pdf")) {
static PdfFileWriter PdfWriter;
ret = &PdfWriter;
} else if(StringEndsIn(filename, ".svg")) {
} else if(FilenameHasExtension(filename, ".svg")) {
static SvgFileWriter SvgWriter;
ret = &SvgWriter;
} else if(StringEndsIn(filename, ".plt")||StringEndsIn(filename, ".hpgl")) {
} else if(FilenameHasExtension(filename, ".plt")||FilenameHasExtension(filename, ".hpgl")) {
static HpglFileWriter HpglWriter;
ret = &HpglWriter;
} else if(StringEndsIn(filename, ".step")||StringEndsIn(filename, ".stp")) {
} else if(FilenameHasExtension(filename, ".step")||FilenameHasExtension(filename, ".stp")) {
static Step2dFileWriter Step2dWriter;
ret = &Step2dWriter;
} else if(StringEndsIn(filename, ".txt")) {
} else if(FilenameHasExtension(filename, ".txt")) {
static GCodeFileWriter GCodeWriter;
ret = &GCodeWriter;
} else {
@ -417,13 +417,13 @@ VectorFileWriter *VectorFileWriter::ForFile(const char *filename) {
"filename '%s'; try "
".step, .stp, .dxf, .svg, .plt, .hpgl, .pdf, .txt, "
".eps, or .ps.",
filename);
filename.c_str());
return NULL;
}
FILE *f = fopen(filename, "wb");
FILE *f = fopen(filename.c_str(), "wb");
if(!f) {
Error("Couldn't write to '%s'", filename);
Error("Couldn't write to '%s'", filename.c_str());
return NULL;
}
ret->f = f;
@ -558,29 +558,29 @@ void VectorFileWriter::BezierAsNonrationalCubic(SBezier *sb, int depth) {
//-----------------------------------------------------------------------------
// 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);
if(m->IsEmpty()) {
Error("Active group mesh is empty; nothing to export.");
return;
}
FILE *f = fopen(filename, "wb");
FILE *f = fopen(filename.c_str(), "wb");
if(!f) {
Error("Couldn't write to '%s'", filename);
Error("Couldn't write to '%s'", filename.c_str());
return;
}
if(StringEndsIn(filename, ".stl")) {
if(FilenameHasExtension(filename, ".stl")) {
ExportMeshAsStlTo(f, m);
} else if(StringEndsIn(filename, ".obj")) {
} else if(FilenameHasExtension(filename, ".obj")) {
ExportMeshAsObjTo(f, m);
} else if(StringEndsIn(filename, ".js")) {
} else if(FilenameHasExtension(filename, ".js")) {
SEdgeList *e = &(SK.GetGroup(SS.GW.activeGroup)->displayEdges);
ExportMeshAsThreeJsTo(f, filename, m, e);
} else {
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);
@ -658,7 +658,7 @@ void SolveSpaceUI::ExportMeshAsObjTo(FILE *f, SMesh *sm) {
//-----------------------------------------------------------------------------
// 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)
{
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 largerBoundZ = max(largerBoundXY, (bndh.z - bndl.z + 1));
char *baseFilename = (char *) MemAlloc(strlen(filename));
const char *lastSlash;
std::string baseFilename = filename;
#ifdef WIN32
lastSlash = strrchr(filename, '\\');
size_t lastSlash = baseFilename.rfind('\\');
#else
lastSlash = strrchr(filename, '/');
size_t lastSlash = baseFilename.rfind('/');
#endif
if(!lastSlash) oops();
lastSlash++; // Point one past last slash.
strcpy(baseFilename, lastSlash); // Copy the file w/ extension.
*strrchr(baseFilename, '.') = '\0'; // Strip extension.
if(lastSlash == std::string::npos) oops();
baseFilename.erase(0, lastSlash + 1);
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]) &&
/* also permit UTF-8 */ !((unsigned char)baseFilename[i] >= 0x80))
baseFilename[i] = '_';
}
fprintf(f, html, baseFilename, baseFilename);
fprintf(f, html, baseFilename.c_str(), baseFilename.c_str());
fprintf(f, "var three_js_%s = {\n"
" bounds: {\n"
" x: %f, y: %f, near: %f, far: %f, z: %f, edgeBias: %f\n"
" },\n",
baseFilename,
baseFilename.c_str(),
largerBoundXY,
largerBoundXY,
1.0,
@ -904,8 +904,6 @@ void SolveSpaceUI::ExportMeshAsThreeJsTo(FILE *f, const char * filename, SMesh *
largerBoundZ,
largerBoundZ / 250);
MemFree(baseFilename);
// Output lighting information.
fputs(" lights: {\n"
" 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
// 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;
// No guarantee that the back buffer contains anything valid right now,
// so repaint the scene. And hide the toolbar too.
@ -1003,7 +1001,7 @@ void SolveSpaceUI::ExportAsPngTo(const char *filename) {
SS.GW.Paint();
SS.showToolbar = prevShowToolbar;
FILE *f = fopen(filename, "wb");
FILE *f = fopen(filename.c_str(), "wb");
if(!f) goto err;
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;
err:
Error("Error writing PNG file '%s'", filename);
Error("Error writing PNG file '%s'", filename.c_str());
if(f) fclose(f);
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);
SShell *shell = &(g->runningShell);
@ -305,9 +305,9 @@ void StepFileWriter::ExportSurfacesTo(char *file) {
return;
}
f = fopen(file, "wb");
f = fopen(filename.c_str(), "wb");
if(!f) {
Error("Couldn't write to '%s'", file);
Error("Couldn't write to '%s'", filename.c_str());
return;
}

View File

@ -201,7 +201,7 @@ const SolveSpaceUI::SaveTable SolveSpaceUI::SAVED[] = {
union SAVEDptr {
IdList<EntityMap,EntityId> M;
NameStr N;
char P[MAX_PATH];
/* std::string P */
bool b;
RgbaColor c;
int d;
@ -225,7 +225,7 @@ void SolveSpaceUI::SaveUsingTable(int type) {
fprintf(fh, "%s=", SAVED[i].desc);
switch(fmt) {
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 'c': fprintf(fh, "%08x", p->c.ToPackedInt()); 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
// will be exported. We reload the imported files because that rewrites
// the impFileRel for our possibly-new filename.
@ -258,9 +258,9 @@ bool SolveSpaceUI::SaveToFile(const char *filename) {
SS.ReloadAllImported();
SS.GenerateAll(0, INT_MAX);
fh = fopen(filename, "wb");
fh = fopen(filename.c_str(), "wb");
if(!fh) {
Error("Couldn't write to file '%s'", filename);
Error("Couldn't write to file '%s'", filename.c_str());
return false;
}
@ -385,7 +385,7 @@ void SolveSpaceUI::LoadUsingTable(char *key, char *val) {
break;
case 'P':
if(strlen(val)+1 < MAX_PATH) strcpy(p->P, val);
*((std::string*)p) = val;
break;
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;
fileLoadError = false;
fh = fopen(filename, "rb");
fh = fopen(filename.c_str(), "rb");
if(!fh) {
Error("Couldn't read from file '%s'", filename);
Error("Couldn't read from file '%s'", filename.c_str());
return false;
}
@ -503,13 +503,13 @@ bool SolveSpaceUI::LoadFromFile(const char *filename) {
return true;
}
bool SolveSpaceUI::LoadEntitiesFromFile(const char *file, EntityList *le,
bool SolveSpaceUI::LoadEntitiesFromFile(const std::string &filename, EntityList *le,
SMesh *m, SShell *sh)
{
SSurface srf = {};
SCurve crv = {};
fh = fopen(file, "rb");
fh = fopen(filename.c_str(), "rb");
if(!fh) return false;
le->Clear();
@ -652,7 +652,7 @@ void SolveSpaceUI::ReloadAllImported(void) {
// Change backslashes to forward slashes on Unix.
// Done unconditionally to get the displayed filename
// 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] == '\\')
g->impFileRel[j] = '/';
}
@ -662,39 +662,35 @@ void SolveSpaceUI::ReloadAllImported(void) {
g->impMesh.Clear();
g->impShell.Clear();
FILE *test = fopen(g->impFile, "rb");
FILE *test = fopen(g->impFile.c_str(), "rb");
if(test) {
fclose(test); // okay, exists
} else {
// It doesn't exist. Perhaps the entire tree has moved, and we
// can use the relative filename to get us back.
if(SS.saveFile[0]) {
char fromRel[MAX_PATH];
strcpy(fromRel, g->impFileRel);
MakePathAbsolute(SS.saveFile, fromRel);
test = fopen(fromRel, "rb");
if(!SS.saveFile.empty()) {
std::string fromRel = MakePathAbsolute(SS.saveFile, g->impFileRel);
test = fopen(fromRel.c_str(), "rb");
if(test) {
fclose(test);
// It worked, this is our new absolute path
strcpy(g->impFile, fromRel);
g->impFile = fromRel;
}
}
}
if(LoadEntitiesFromFile(g->impFile,
&(g->impEntity), &(g->impMesh), &(g->impShell)))
if(LoadEntitiesFromFile(g->impFile, &(g->impEntity), &(g->impMesh), &(g->impShell)))
{
if(SS.saveFile[0]) {
if(!SS.saveFile.empty()) {
// Record the imported file's name relative to our filename;
// if the entire tree moves, then everything will still work
strcpy(g->impFileRel, g->impFile);
MakePathRelative(SS.saveFile, g->impFileRel);
g->impFileRel = MakePathRelative(SS.saveFile, g->impFile);
} else {
// We're not yet saved, so can't make it absolute
strcpy(g->impFileRel, g->impFile);
g->impFileRel = g->impFile;
}
} 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;
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;
}
@ -187,30 +187,36 @@ void Group::MenuGroup(int id) {
case GraphicsWindow::MNU_GROUP_IMPORT: {
g.type = IMPORTED;
g.opA = SS.GW.activeGroup;
if(strlen(g.impFile) == 0) {
if(g.impFile.empty()) {
if(!GetOpenFile(g.impFile, SLVS_EXT, SLVS_PATTERN)) return;
}
// Assign the default name of the group based on the name of
// the imported file.
char groupName[MAX_PATH];
strcpy(groupName, g.impFile);
char *dot = strrchr(groupName, '.');
if(dot) *dot = '\0';
std::string groupName = g.impFile;
size_t pos;
char *s, *start = groupName;
for(s = groupName; *s; s++) {
if(*s == '/' || *s == '\\') {
start = s + 1;
} else if(isalnum(*s)) {
pos = groupName.rfind('.');
if(pos != std::string::npos)
groupName.erase(pos);
pos = groupName.find('/');
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
} else {
// 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 {
g.name.strcpy("import");
}

View File

@ -63,15 +63,6 @@
#endif
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 */
/* Why not just use GSettings? Two reasons. It doesn't allow to easily see
@ -240,6 +231,13 @@ void ScheduleLater() {
/* 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 {
public:
GlWidget() : _offscreen(NULL) {
@ -703,9 +701,9 @@ void PaintGraphics(void) {
Glib::MainContext::get_default()->iteration(false);
}
void SetCurrentFilename(const char *filename) {
if(filename) {
GW->set_title(std::string("SolveSpace - ") + filename);
void SetCurrentFilename(const std::string &filename) {
if(!filename.empty()) {
GW->set_title("SolveSpace - " + filename);
} else {
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");
chooser.set_filename(file);
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);
if(chooser.run() == Gtk::RESPONSE_OK) {
CnfFreezeString(chooser.get_current_folder().c_str(), "FileChooserPath");
strcpy(file, chooser.get_filename().c_str());
CnfFreezeString(chooser.get_current_folder(), "FileChooserPath");
file = chooser.get_filename();
return true;
} else {
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::FILE_CHOOSER_ACTION_SAVE);
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) {
CnfFreezeString(chooser.get_current_folder(), "FileChooserPath");
strcpy(file, chooser.get_filename().c_str());
file = chooser.get_filename();
return true;
} else {
return false;
@ -1415,15 +1413,14 @@ void LoadAllFontFiles(void) {
FcFontSet *fs = FcFontList(0, pat, os);
for(int i = 0; i < fs->nfont; i++) {
FcChar8 *filename = FcPatternFormat(fs->fonts[i], (const FcChar8*) "%{file}");
Glib::ustring ufilename = (char*) filename;
if(ufilename.length() > 4 &&
ufilename.substr(ufilename.length() - 4, 4).lowercase() == ".ttf") {
FcChar8 *filenameFC = FcPatternFormat(fs->fonts[i], (const FcChar8*) "%{file}");
std::string filename = (char*) filenameFC;
if(FilenameHasExtension(filename, ".ttf")) {
TtfFont tf = {};
strcpy(tf.fontFile, (char*) filename);
tf.fontFile = filename;
SS.fonts.l.Add(&tf);
}
FcStrFree(filename);
FcStrFree(filenameFC);
}
FcFontSetDestroy(fs);

View File

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

View File

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

View File

@ -114,16 +114,12 @@ class ExprVector;
class ExprQuaternion;
class RgbaColor;
#ifndef MAX_PATH
# define MAX_PATH PATH_MAX
#endif
//================
// From the platform-specific code.
#define MAX_RECENT 8
#define RECENT_OPEN (0xf000)
#define RECENT_IMPORT (0xf100)
extern char RecentFile[MAX_RECENT][MAX_PATH];
extern std::string RecentFile[MAX_RECENT];
void RefreshRecentMenus(void);
#define SAVE_YES (1)
@ -196,9 +192,9 @@ int LoadAutosaveYesNo(void);
// Comma-separated value, like a spreadsheet would use
#define CSV_PATTERN PAT1("CSV File", "csv") ENDPAT
#define CSV_EXT "csv"
bool GetSaveFile(char *file, const char *defExtension, const char *selPattern);
bool GetOpenFile(char *file, const char *defExtension, const char *selPattern);
void GetAbsoluteFilename(char *file);
bool GetSaveFile(std::string &filename, const char *defExtension, const char *selPattern);
bool GetOpenFile(std::string &filename, const char *defExtension, const char *selPattern);
std::string GetAbsoluteFilename(const std::string &filename);
void LoadAllFontFiles(void);
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)", \
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 DoMessageBox(const char *str, int rows, int cols, bool error);
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 a31, double a32, double a33, double a34,
double a41, double a42, double a43, double a44);
void MakePathRelative(const char *base, char *path);
void MakePathAbsolute(const char *base, char *path);
std::string MakePathRelative(const std::string &base, const std::string &path);
std::string MakePathAbsolute(const std::string &base, const std::string &path);
bool MakeAcceleratorLabel(int accel, char *out);
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 Error(const char *str, ...);
void CnfFreezeBool(bool v, const std::string &name);
@ -448,9 +444,9 @@ public:
int x, y;
} IntPoint;
char fontFile[MAX_PATH];
NameStr name;
bool loaded;
std::string fontFile;
NameStr name;
bool loaded;
// The font itself, plus the mapping from ASCII codes to glyphs
int useGlyph[256];
@ -484,7 +480,7 @@ public:
void LoadGlyph(int index);
bool LoadFontFromFile(bool nameOnly);
const char *FontFileBaseName(void);
std::string FontFileBaseName(void);
void Flush(void);
void Handle(int *dx, int x, int y, bool onCurve);
@ -504,13 +500,13 @@ public:
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);
};
class StepFileWriter {
public:
void ExportSurfacesTo(char *filename);
void ExportSurfacesTo(const std::string &filename);
void WriteHeader(void);
void WriteProductHeader(void);
int ExportCurve(SBezier *sb);
@ -536,7 +532,7 @@ public:
static double MmToPts(double mm);
static VectorFileWriter *ForFile(const char *file);
static VectorFileWriter *ForFile(const std::string &filename);
void Output(SBezierLoopSetSet *sblss, SMesh *sm);
@ -791,18 +787,18 @@ public:
// The platform-dependent code calls this before entering the msg loop
void Init(void);
bool OpenFile(const char *filename);
bool OpenFile(const std::string &filename);
void Exit(void);
// File load/save routines, including the additional files that get
// loaded when we have import groups.
FILE *fh;
void AfterNewFile(void);
static void RemoveFromRecentList(const char *file);
static void AddToRecentList(const char *file);
char saveFile[MAX_PATH];
bool fileLoadError;
bool unsaved;
static void RemoveFromRecentList(const std::string &filename);
static void AddToRecentList(const std::string &filename);
std::string saveFile;
bool fileLoadError;
bool unsaved;
typedef struct {
char type;
const char *desc;
@ -829,20 +825,20 @@ public:
void UpdateWindowTitle(void);
void ClearExisting(void);
void NewFile(void);
bool SaveToFile(const char *filename);
bool LoadAutosaveFor(const char *filename);
bool LoadFromFile(const char *filename);
bool LoadEntitiesFromFile(const char *filename, EntityList *le,
bool SaveToFile(const std::string &filename);
bool LoadAutosaveFor(const std::string &filename);
bool LoadFromFile(const std::string &filename);
bool LoadEntitiesFromFile(const std::string &filename, EntityList *le,
SMesh *m, SShell *sh);
void ReloadAllImported(void);
// And the various export options
void ExportAsPngTo(const char *file);
void ExportMeshTo(const char *file);
void ExportAsPngTo(const std::string &filename);
void ExportMeshTo(const std::string &filename);
void ExportMeshAsStlTo(FILE *f, SMesh *sm);
void ExportMeshAsObjTo(FILE *f, SMesh *sm);
void ExportMeshAsThreeJsTo(FILE *f, const char * filename, SMesh *sm, SEdgeList *sel);
void ExportViewOrWireframeTo(const char *file, bool wireframe);
void ExportSectionTo(const char *file);
void ExportMeshAsThreeJsTo(FILE *f, const std::string &filename, SMesh *sm, SEdgeList *sel);
void ExportViewOrWireframeTo(const std::string &filename, bool wireframe);
void ExportSectionTo(const std::string &filename);
void ExportWireframeCurves(SEdgeList *sel, SBezierList *sbl,
VectorFileWriter *out);
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_info *info_ptr = NULL;
char importFile[MAX_PATH] = "";
std::string importFile;
if(!GetOpenFile(importFile, PNG_EXT, PNG_PATTERN)) goto err;
f = fopen(importFile, "rb");
f = fopen(importFile.c_str(), "rb");
if(!f) goto err;
uint8_t header[8];

View File

@ -331,7 +331,7 @@ void TextWindow::ShowGroupInfo(void) {
}
} else if(g->type == Group::IMPORTED) {
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",
g->scale,
&TextWindow::ScreenChangeGroupScale, g->h.v);

View File

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

View File

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

View File

@ -6,45 +6,46 @@
//-----------------------------------------------------------------------------
#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;
const char *p;
char base[MAX_PATH], path[MAX_PATH], out[MAX_PATH];
std::string base, path;
// Convert everything to lowercase
p = basep;
for(i = 0; *p; p++) {
base[i++] = (char)tolower(*p);
}
base[i++] = '\0';
p = pathp;
for(i = 0; *p; p++) {
path[i++] = (char)tolower(*p);
}
path[i++] = '\0';
// FIXME: This is not generally safe to do on Linux/FreeBSD
// FIXME: tolower will try to respect locale on POSIX. This is, obviously, broken
p = &basep[0];
for(i = 0; *p; p++)
base += (char)tolower(*p);
p = &pathp[0];
for(i = 0; *p; p++)
path += (char)tolower(*p);
// Find the length of the common prefix
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])) return; // weird, prefix is entire string
if(com == 0) return; // maybe on different drive letters?
if(com == base.length() || com == path.length())
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
// 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--;
}
if(com == 0) return;
if(com == 0) return pathp;
int sections = 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(secLen == 2 && memcmp(base+secStart, "..", 2)==0) return;
if(secLen == 1 && memcmp(base+secStart, ".", 1)==0) return;
if(secLen == 2 && memcmp(&base[secStart], "..", 2)==0) return pathp;
if(secLen == 1 && memcmp(&base[secStart], ".", 1)==0) return pathp;
sections++;
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
// directory in the relative path name
strcpy(out, "");
std::string out;
for(i = 0; i < sections; i++) {
strcat(out, "../");
out += "../";
}
// comparison is case-insensitive, but output preserves input case
strcat(out, pathp+com);
strcpy(pathp, out);
out += pathp.substr(com);
return out;
}
void SolveSpace::MakePathAbsolute(const char *basep, char *pathp) {
char out[MAX_PATH];
strcpy(out, basep);
std::string SolveSpace::MakePathAbsolute(const std::string &basep, const std::string &pathp) {
std::string out = basep;
// Chop off the filename
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(i < 0) return; // base is not an absolute path, or something?
out[i+1] = '\0';
if(i < 0) return pathp; // base is not an absolute path, or something?
out.resize(i + 1);
strcat(out, pathp);
GetAbsoluteFilename(out);
strcpy(pathp, out);
out += pathp;
return GetAbsoluteFilename(out);
}
bool SolveSpace::StringAllPrintable(const char *str)
@ -95,14 +92,14 @@ bool SolveSpace::StringAllPrintable(const char *str)
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;
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;
}
}

View File

@ -39,7 +39,6 @@ static struct {
int x, y;
} LastMousePos;
char SolveSpace::RecentFile[MAX_RECENT][MAX_PATH];
HMENU SubMenus[100];
HMENU RecentOpenMenu, RecentImportMenu;
@ -376,7 +375,8 @@ std::string SolveSpace::CnfThawString(const std::string &val, const std::string
return val;
}
std::string newval(len, '\0');
std::string newval;
newval.resize(len - 1);
if(RegQueryValueEx(SolveSpace, &name[0], NULL,
NULL, (BYTE*) &newval[0], &len) != ERROR_SUCCESS) {
RegCloseKey(SolveSpace);
@ -412,10 +412,9 @@ static void ThawWindowPos(HWND hwnd, const std::string &name)
ShowWindow(hwnd, SW_MAXIMIZE);
}
void SolveSpace::SetCurrentFilename(const char *filename) {
if(filename) {
std::string title = std::string("SolveSpace - ") + filename;
SetWindowText(GraphicsWnd, title.c_str());
void SolveSpace::SetCurrentFilename(const std::string &filename) {
if(!filename.empty()) {
SetWindowText(GraphicsWnd, ("SolveSpace - " + filename).c_str());
} else {
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.
//-----------------------------------------------------------------------------
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.hInstance = Instance;
ofn.hwndOwner = GraphicsWnd;
ofn.lpstrFilter = selPattern;
ofn.lpstrDefExt = defExtension;
ofn.lpstrFile = file;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFile = filenameC;
ofn.nMaxFile = sizeof(filenameC);
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
EnableWindow(GraphicsWnd, false);
@ -981,20 +987,25 @@ bool SolveSpace::GetOpenFile(char *file, const char *defExtension, const char *s
EnableWindow(GraphicsWnd, true);
SetForegroundWindow(GraphicsWnd);
if(r) filename = filenameC;
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.hInstance = Instance;
ofn.hwndOwner = GraphicsWnd;
ofn.lpstrFilter = selPattern;
ofn.lpstrDefExt = defExtension;
ofn.lpstrFile = file;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFile = filenameC;
ofn.nMaxFile = sizeof(filenameC);
ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
EnableWindow(GraphicsWnd, false);
@ -1006,6 +1017,7 @@ bool SolveSpace::GetSaveFile(char *file, const char *defExtension, const char *s
EnableWindow(GraphicsWnd, true);
SetForegroundWindow(GraphicsWnd);
if(r) filename = filenameC;
return r ? true : false;
}
@ -1057,22 +1069,15 @@ int SolveSpace::LoadAutosaveYesNo(void)
void SolveSpace::LoadAllFontFiles(void)
{
std::string fontsDir(MAX_PATH, '\0');
fontsDir.resize(GetWindowsDirectory(&fontsDir[0], fontsDir.length()));
fontsDir += "\\fonts\\";
WIN32_FIND_DATA wfd;
char dir[MAX_PATH];
GetWindowsDirectory(dir, MAX_PATH - 30);
strcat(dir, "\\fonts\\*.ttf");
HANDLE h = FindFirstFile(dir, &wfd);
HANDLE h = FindFirstFile((fontsDir + "*.ttf").c_str(), &wfd);
while(h != INVALID_HANDLE_VALUE) {
TtfFont tf = {};
char fullPath[MAX_PATH];
GetWindowsDirectory(fullPath, MAX_PATH - (30 + (UINT)strlen(wfd.cFileName)));
strcat(fullPath, "\\fonts\\");
strcat(fullPath, wfd.cFileName);
strcpy(tf.fontFile, fullPath);
tf.fontFile = fontsDir + wfd.cFileName;
SS.fonts.l.Add(&tf);
if(!FindNextFile(h, &wfd)) break;
@ -1122,9 +1127,8 @@ static void DoRecent(HMENU m, int base)
;
int i, c = 0;
for(i = 0; i < MAX_RECENT; i++) {
char *s = RecentFile[i];
if(*s) {
AppendMenu(m, MF_STRING, base+i, s);
if(!RecentFile[i].empty()) {
AppendMenu(m, MF_STRING, base + i, RecentFile[i].c_str());
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
// strip any quotation marks, and make it absolute.
char file[MAX_PATH] = "";
if(strlen(lpCmdLine)+1 < MAX_PATH) {
char *s = lpCmdLine;
while(*s == ' ' || *s == '"') s++;
strcpy(file, s);
s = strrchr(file, '"');
if(s) *s = '\0';
}
if(*file != '\0') {
GetAbsoluteFilename(file);
}
std::string filename = lpCmdLine;
size_t pos;
pos = filename.find_last_not_of("\"");
if(pos != std::string::npos)
filename.erase(pos + 1);
pos = filename.find_first_not_of(" \"");
if(pos != std::string::npos)
filename.erase(0, pos);
if(!filename.empty())
filename = GetAbsoluteFilename(filename);
#ifdef HAVE_SPACEWARE
// 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
SS.Init();
if(strcmp(file, ""))
SS.OpenFile(file);
if(!filename.empty())
SS.OpenFile(filename);
// And now it's the message loop. All calls in to the rest of the code
// will be from the wndprocs.

View File

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