2016-11-29 10:57:41 +08:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Our main() function for the command-line interface.
|
|
|
|
//
|
|
|
|
// Copyright 2016 whitequark
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "solvespace.h"
|
|
|
|
|
2017-01-25 03:40:30 +08:00
|
|
|
static void ShowUsage(const std::string &cmd) {
|
|
|
|
fprintf(stderr, "Usage: %s <command> <options> <filename> [filename...]", cmd.c_str());
|
2016-11-29 10:57:41 +08:00
|
|
|
//-----------------------------------------------------------------------------> 80 col */
|
|
|
|
fprintf(stderr, R"(
|
|
|
|
When run, performs an action specified by <command> on every <filename>.
|
|
|
|
|
2017-03-10 01:23:47 +08:00
|
|
|
Common options:
|
2016-11-29 10:57:41 +08:00
|
|
|
-o, --output <pattern>
|
2017-01-25 03:54:44 +08:00
|
|
|
For an input file <name>.slvs, replaces the '%%' symbol in <pattern>
|
|
|
|
with <name> and uses it as output file. For example, when using
|
|
|
|
--output %%-2d.png for input files f/a.slvs and f/b.slvs, output files
|
|
|
|
f/a-2d.png and f/b-2d.png will be written.
|
2016-11-29 10:57:41 +08:00
|
|
|
-v, --view <direction>
|
|
|
|
Selects the camera direction. <direction> can be one of "top", "bottom",
|
|
|
|
"left", "right", "front", "back", or "isometric".
|
|
|
|
-t, --chord-tol <tolerance>
|
|
|
|
Selects the chord tolerance, used for converting exact curves to
|
|
|
|
piecewise linear, and exact surfaces into triangle meshes.
|
|
|
|
For export commands, the unit is mm, and the default is 1.0 mm.
|
|
|
|
For non-export commands, the unit is %%, and the default is 1.0 %%.
|
|
|
|
|
2017-03-10 01:23:47 +08:00
|
|
|
Commands:
|
2016-11-29 10:57:41 +08:00
|
|
|
thumbnail --output <pattern> --size <size> --view <direction>
|
|
|
|
[--chord-tol <tolerance>]
|
|
|
|
Outputs a rendered view of the sketch, like the SolveSpace GUI would.
|
|
|
|
<size> is <width>x<height>, in pixels. Graphics acceleration is
|
|
|
|
not used, and the output may look slightly different from the GUI.
|
|
|
|
export-view --output <pattern> --view <direction> [--chord-tol <tolerance>]
|
|
|
|
Exports a view of the sketch, in a 2d vector format.
|
|
|
|
export-wireframe --output <pattern> [--chord-tol <tolerance>]
|
|
|
|
Exports a wireframe of the sketch, in a 3d vector format.
|
|
|
|
export-mesh --output <pattern> [--chord-tol <tolerance>]
|
|
|
|
Exports a triangle mesh of solids in the sketch, with exact surfaces
|
|
|
|
being triangulated first.
|
|
|
|
export-surfaces --output <pattern>
|
|
|
|
Exports exact surfaces of solids in the sketch, if any.
|
2019-05-24 00:22:27 +08:00
|
|
|
regenerate [--chord-tol <tolerance>]
|
2017-01-25 03:55:53 +08:00
|
|
|
Reloads all imported files, regenerates the sketch, and saves it.
|
2019-05-24 00:22:27 +08:00
|
|
|
Note that, although this is not an export command, it uses absolute
|
|
|
|
chord tolerance, and can be used to prepare assemblies for export.
|
2016-11-29 10:57:41 +08:00
|
|
|
)");
|
|
|
|
|
2018-07-18 02:51:00 +08:00
|
|
|
auto FormatListFromFileFilters = [](const std::vector<Platform::FileFilter> &filters) {
|
2016-11-29 10:57:41 +08:00
|
|
|
std::string descr;
|
2018-07-18 02:51:00 +08:00
|
|
|
for(auto filter : filters) {
|
2016-11-29 10:57:41 +08:00
|
|
|
descr += "\n ";
|
2018-07-18 02:51:00 +08:00
|
|
|
descr += filter.name;
|
2016-11-29 10:57:41 +08:00
|
|
|
descr += " (";
|
2018-07-18 02:51:00 +08:00
|
|
|
bool first = true;
|
|
|
|
for(auto extension : filter.extensions) {
|
|
|
|
if(!first) {
|
2016-11-29 10:57:41 +08:00
|
|
|
descr += ", ";
|
|
|
|
}
|
2018-07-18 02:51:00 +08:00
|
|
|
descr += extension;
|
|
|
|
first = false;
|
2016-11-29 10:57:41 +08:00
|
|
|
}
|
|
|
|
descr += ")";
|
|
|
|
}
|
|
|
|
return descr;
|
|
|
|
};
|
|
|
|
|
|
|
|
fprintf(stderr, R"(
|
2017-03-10 01:23:47 +08:00
|
|
|
File formats:
|
2016-11-29 10:57:41 +08:00
|
|
|
thumbnail:%s
|
|
|
|
export-view:%s
|
|
|
|
export-wireframe:%s
|
|
|
|
export-mesh:%s
|
|
|
|
export-surfaces:%s
|
2018-07-18 02:51:00 +08:00
|
|
|
)", FormatListFromFileFilters(Platform::RasterFileFilters).c_str(),
|
|
|
|
FormatListFromFileFilters(Platform::VectorFileFilters).c_str(),
|
|
|
|
FormatListFromFileFilters(Platform::Vector3dFileFilters).c_str(),
|
|
|
|
FormatListFromFileFilters(Platform::MeshFileFilters).c_str(),
|
|
|
|
FormatListFromFileFilters(Platform::SurfaceFileFilters).c_str());
|
2016-11-29 10:57:41 +08:00
|
|
|
}
|
|
|
|
|
2016-12-05 08:25:31 +08:00
|
|
|
static bool RunCommand(const std::vector<std::string> args) {
|
|
|
|
if(args.size() < 2) return false;
|
2016-11-29 10:57:41 +08:00
|
|
|
|
2017-01-25 03:40:30 +08:00
|
|
|
for(const std::string &arg : args) {
|
|
|
|
if(arg == "--help" || arg == "-h") {
|
|
|
|
ShowUsage(args[0]);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-11 22:43:21 +08:00
|
|
|
std::function<void(const Platform::Path &)> runner;
|
2016-11-29 10:57:41 +08:00
|
|
|
|
2017-03-11 22:43:21 +08:00
|
|
|
std::vector<Platform::Path> inputFiles;
|
2016-11-29 10:57:41 +08:00
|
|
|
auto ParseInputFile = [&](size_t &argn) {
|
2016-12-05 08:25:31 +08:00
|
|
|
std::string arg = args[argn];
|
2016-11-29 10:57:41 +08:00
|
|
|
if(arg[0] != '-') {
|
2017-03-11 22:43:21 +08:00
|
|
|
inputFiles.push_back(Platform::Path::From(arg));
|
2016-11-29 10:57:41 +08:00
|
|
|
return true;
|
|
|
|
} else return false;
|
|
|
|
};
|
|
|
|
|
|
|
|
std::string outputPattern;
|
|
|
|
auto ParseOutputPattern = [&](size_t &argn) {
|
2016-12-05 08:25:31 +08:00
|
|
|
if(argn + 1 < args.size() && (args[argn] == "--output" ||
|
|
|
|
args[argn] == "-o")) {
|
2016-11-29 10:57:41 +08:00
|
|
|
argn++;
|
2016-12-05 08:25:31 +08:00
|
|
|
outputPattern = args[argn];
|
2016-11-29 10:57:41 +08:00
|
|
|
return true;
|
|
|
|
} else return false;
|
|
|
|
};
|
|
|
|
|
2016-12-05 08:25:31 +08:00
|
|
|
Vector projUp = {}, projRight = {};
|
2016-11-29 10:57:41 +08:00
|
|
|
auto ParseViewDirection = [&](size_t &argn) {
|
2016-12-05 08:25:31 +08:00
|
|
|
if(argn + 1 < args.size() && (args[argn] == "--view" ||
|
|
|
|
args[argn] == "-v")) {
|
2016-11-29 10:57:41 +08:00
|
|
|
argn++;
|
2016-12-05 08:25:31 +08:00
|
|
|
if(args[argn] == "top") {
|
2016-11-29 10:57:41 +08:00
|
|
|
projRight = Vector::From(1, 0, 0);
|
|
|
|
projUp = Vector::From(0, 1, 0);
|
2016-12-05 08:25:31 +08:00
|
|
|
} else if(args[argn] == "bottom") {
|
2016-11-29 10:57:41 +08:00
|
|
|
projRight = Vector::From(-1, 0, 0);
|
|
|
|
projUp = Vector::From(0, 1, 0);
|
2016-12-05 08:25:31 +08:00
|
|
|
} else if(args[argn] == "left") {
|
2016-11-29 10:57:41 +08:00
|
|
|
projRight = Vector::From(0, 1, 0);
|
|
|
|
projUp = Vector::From(0, 0, 1);
|
2016-12-05 08:25:31 +08:00
|
|
|
} else if(args[argn] == "right") {
|
2016-11-29 10:57:41 +08:00
|
|
|
projRight = Vector::From(0, -1, 0);
|
|
|
|
projUp = Vector::From(0, 0, 1);
|
2016-12-05 08:25:31 +08:00
|
|
|
} else if(args[argn] == "front") {
|
2016-11-29 10:57:41 +08:00
|
|
|
projRight = Vector::From(-1, 0, 0);
|
|
|
|
projUp = Vector::From(0, 0, 1);
|
2016-12-05 08:25:31 +08:00
|
|
|
} else if(args[argn] == "back") {
|
2016-11-29 10:57:41 +08:00
|
|
|
projRight = Vector::From(1, 0, 0);
|
|
|
|
projUp = Vector::From(0, 0, 1);
|
2016-12-05 08:25:31 +08:00
|
|
|
} else if(args[argn] == "isometric") {
|
2016-11-29 10:57:41 +08:00
|
|
|
projRight = Vector::From(0.707, 0.000, -0.707);
|
|
|
|
projUp = Vector::From(-0.408, 0.816, -0.408);
|
|
|
|
} else {
|
2016-12-05 08:25:31 +08:00
|
|
|
fprintf(stderr, "Unrecognized view direction '%s'\n", args[argn].c_str());
|
2016-11-29 10:57:41 +08:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
} else return false;
|
|
|
|
};
|
|
|
|
|
|
|
|
double chordTol = 1.0;
|
|
|
|
auto ParseChordTolerance = [&](size_t &argn) {
|
2018-11-08 12:09:51 +08:00
|
|
|
if(argn + 1 < args.size() && (args[argn] == "--chord-tol" ||
|
2016-12-05 08:25:31 +08:00
|
|
|
args[argn] == "-t")) {
|
2016-11-29 10:57:41 +08:00
|
|
|
argn++;
|
2016-12-05 08:25:31 +08:00
|
|
|
if(sscanf(args[argn].c_str(), "%lf", &chordTol) == 1) {
|
2016-11-29 10:57:41 +08:00
|
|
|
return true;
|
|
|
|
} else return false;
|
|
|
|
} else return false;
|
|
|
|
};
|
|
|
|
|
2017-02-15 10:22:34 +08:00
|
|
|
unsigned width = 0, height = 0;
|
2016-12-05 08:25:31 +08:00
|
|
|
if(args[1] == "thumbnail") {
|
2016-11-29 10:57:41 +08:00
|
|
|
auto ParseSize = [&](size_t &argn) {
|
2016-12-05 08:25:31 +08:00
|
|
|
if(argn + 1 < args.size() && args[argn] == "--size") {
|
2016-11-29 10:57:41 +08:00
|
|
|
argn++;
|
2016-12-05 08:25:31 +08:00
|
|
|
if(sscanf(args[argn].c_str(), "%ux%u", &width, &height) == 2) {
|
2016-11-29 10:57:41 +08:00
|
|
|
return true;
|
|
|
|
} else return false;
|
|
|
|
} else return false;
|
|
|
|
};
|
|
|
|
|
2016-12-05 08:25:31 +08:00
|
|
|
for(size_t argn = 2; argn < args.size(); argn++) {
|
2016-11-29 10:57:41 +08:00
|
|
|
if(!(ParseInputFile(argn) ||
|
|
|
|
ParseOutputPattern(argn) ||
|
|
|
|
ParseViewDirection(argn) ||
|
|
|
|
ParseChordTolerance(argn) ||
|
|
|
|
ParseSize(argn))) {
|
2016-12-05 08:25:31 +08:00
|
|
|
fprintf(stderr, "Unrecognized option '%s'.\n", args[argn].c_str());
|
2016-11-29 10:57:41 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(width == 0 || height == 0) {
|
|
|
|
fprintf(stderr, "Non-zero viewport size must be specified.\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(EXACT(projUp.Magnitude() == 0 || projRight.Magnitude() == 0)) {
|
|
|
|
fprintf(stderr, "View direction must be specified.\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-03-11 22:43:21 +08:00
|
|
|
runner = [&](const Platform::Path &output) {
|
2018-07-13 03:29:44 +08:00
|
|
|
Camera camera = {};
|
|
|
|
camera.pixelRatio = 1;
|
|
|
|
camera.gridFit = true;
|
|
|
|
camera.width = width;
|
|
|
|
camera.height = height;
|
|
|
|
camera.projUp = SS.GW.projUp;
|
|
|
|
camera.projRight = SS.GW.projRight;
|
2016-11-29 10:57:41 +08:00
|
|
|
|
2018-07-13 03:29:44 +08:00
|
|
|
SS.GW.projUp = projUp;
|
|
|
|
SS.GW.projRight = projRight;
|
|
|
|
SS.GW.scale = SS.GW.ZoomToFit(camera);
|
|
|
|
camera.scale = SS.GW.scale;
|
2016-11-29 10:57:41 +08:00
|
|
|
SS.GenerateAll();
|
2018-07-13 03:29:44 +08:00
|
|
|
|
2018-07-18 10:30:40 +08:00
|
|
|
CairoPixmapRenderer pixmapCanvas;
|
|
|
|
pixmapCanvas.antialias = true;
|
|
|
|
pixmapCanvas.SetLighting(SS.GW.GetLighting());
|
|
|
|
pixmapCanvas.SetCamera(camera);
|
|
|
|
pixmapCanvas.Init();
|
|
|
|
|
|
|
|
pixmapCanvas.NewFrame();
|
|
|
|
SS.GW.Draw(&pixmapCanvas);
|
|
|
|
pixmapCanvas.FlushFrame();
|
|
|
|
pixmapCanvas.ReadFrame()->WritePng(output, /*flip=*/true);
|
|
|
|
|
|
|
|
pixmapCanvas.Clear();
|
2016-11-29 10:57:41 +08:00
|
|
|
};
|
2016-12-05 08:25:31 +08:00
|
|
|
} else if(args[1] == "export-view") {
|
|
|
|
for(size_t argn = 2; argn < args.size(); argn++) {
|
2016-11-29 10:57:41 +08:00
|
|
|
if(!(ParseInputFile(argn) ||
|
|
|
|
ParseOutputPattern(argn) ||
|
|
|
|
ParseViewDirection(argn) ||
|
|
|
|
ParseChordTolerance(argn))) {
|
2016-12-05 08:25:31 +08:00
|
|
|
fprintf(stderr, "Unrecognized option '%s'.\n", args[argn].c_str());
|
2016-11-29 10:57:41 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(EXACT(projUp.Magnitude() == 0 || projRight.Magnitude() == 0)) {
|
|
|
|
fprintf(stderr, "View direction must be specified.\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-03-11 22:43:21 +08:00
|
|
|
runner = [&](const Platform::Path &output) {
|
2016-11-29 10:57:41 +08:00
|
|
|
SS.GW.projRight = projRight;
|
|
|
|
SS.GW.projUp = projUp;
|
|
|
|
SS.exportChordTol = chordTol;
|
|
|
|
|
|
|
|
SS.ExportViewOrWireframeTo(output, /*exportWireframe=*/false);
|
|
|
|
};
|
2016-12-05 08:25:31 +08:00
|
|
|
} else if(args[1] == "export-wireframe") {
|
|
|
|
for(size_t argn = 2; argn < args.size(); argn++) {
|
2016-11-29 10:57:41 +08:00
|
|
|
if(!(ParseInputFile(argn) ||
|
|
|
|
ParseOutputPattern(argn) ||
|
|
|
|
ParseChordTolerance(argn))) {
|
2016-12-05 08:25:31 +08:00
|
|
|
fprintf(stderr, "Unrecognized option '%s'.\n", args[argn].c_str());
|
2016-11-29 10:57:41 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-11 22:43:21 +08:00
|
|
|
runner = [&](const Platform::Path &output) {
|
2016-11-29 10:57:41 +08:00
|
|
|
SS.exportChordTol = chordTol;
|
|
|
|
|
|
|
|
SS.ExportViewOrWireframeTo(output, /*exportWireframe=*/true);
|
|
|
|
};
|
2016-12-05 08:25:31 +08:00
|
|
|
} else if(args[1] == "export-mesh") {
|
|
|
|
for(size_t argn = 2; argn < args.size(); argn++) {
|
2016-11-29 10:57:41 +08:00
|
|
|
if(!(ParseInputFile(argn) ||
|
|
|
|
ParseOutputPattern(argn) ||
|
|
|
|
ParseChordTolerance(argn))) {
|
2016-12-05 08:25:31 +08:00
|
|
|
fprintf(stderr, "Unrecognized option '%s'.\n", args[argn].c_str());
|
2016-11-29 10:57:41 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-11 22:43:21 +08:00
|
|
|
runner = [&](const Platform::Path &output) {
|
2016-11-29 10:57:41 +08:00
|
|
|
SS.exportChordTol = chordTol;
|
|
|
|
|
|
|
|
SS.ExportMeshTo(output);
|
|
|
|
};
|
2016-12-05 08:25:31 +08:00
|
|
|
} else if(args[1] == "export-surfaces") {
|
|
|
|
for(size_t argn = 2; argn < args.size(); argn++) {
|
2016-11-29 10:57:41 +08:00
|
|
|
if(!(ParseInputFile(argn) ||
|
|
|
|
ParseOutputPattern(argn))) {
|
2016-12-05 08:25:31 +08:00
|
|
|
fprintf(stderr, "Unrecognized option '%s'.\n", args[argn].c_str());
|
2016-11-29 10:57:41 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-11 22:43:21 +08:00
|
|
|
runner = [&](const Platform::Path &output) {
|
2016-11-29 10:57:41 +08:00
|
|
|
StepFileWriter sfw = {};
|
|
|
|
sfw.ExportSurfacesTo(output);
|
|
|
|
};
|
2017-01-25 03:55:53 +08:00
|
|
|
} else if(args[1] == "regenerate") {
|
|
|
|
for(size_t argn = 2; argn < args.size(); argn++) {
|
2019-05-24 00:22:27 +08:00
|
|
|
if(!(ParseInputFile(argn) ||
|
|
|
|
ParseChordTolerance(argn))) {
|
2017-01-25 03:55:53 +08:00
|
|
|
fprintf(stderr, "Unrecognized option '%s'.\n", args[argn].c_str());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
outputPattern = "%.slvs";
|
|
|
|
|
2017-03-11 22:43:21 +08:00
|
|
|
runner = [&](const Platform::Path &output) {
|
2019-05-24 00:22:27 +08:00
|
|
|
SS.exportChordTol = chordTol;
|
|
|
|
SS.exportMode = true;
|
|
|
|
|
2017-01-25 03:55:53 +08:00
|
|
|
SS.SaveToFile(output);
|
|
|
|
};
|
2016-11-29 10:57:41 +08:00
|
|
|
} else {
|
2016-12-05 08:25:31 +08:00
|
|
|
fprintf(stderr, "Unrecognized command '%s'.\n", args[1].c_str());
|
2016-11-29 10:57:41 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(outputPattern.empty()) {
|
|
|
|
fprintf(stderr, "An output pattern must be specified.\n");
|
|
|
|
return false;
|
|
|
|
} else if(outputPattern.find('%') == std::string::npos && inputFiles.size() > 1) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Output pattern must include a %% symbol when using multiple inputs!\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-08-21 03:33:23 +08:00
|
|
|
if(inputFiles.empty()) {
|
2016-11-29 10:57:41 +08:00
|
|
|
fprintf(stderr, "At least one input file must be specified.\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-03-11 22:43:21 +08:00
|
|
|
for(const Platform::Path &inputFile : inputFiles) {
|
|
|
|
Platform::Path absInputFile = inputFile.Expand(/*fromCurrentDirectory=*/true);
|
2016-12-05 08:25:31 +08:00
|
|
|
|
2017-03-11 22:43:21 +08:00
|
|
|
Platform::Path outputFile = Platform::Path::From(outputPattern);
|
|
|
|
size_t replaceAt = outputFile.raw.find('%');
|
2016-11-29 10:57:41 +08:00
|
|
|
if(replaceAt != std::string::npos) {
|
2017-03-11 22:43:21 +08:00
|
|
|
Platform::Path outputSubst = inputFile.Parent();
|
2018-05-10 23:31:55 +08:00
|
|
|
if(outputSubst.IsEmpty()) {
|
|
|
|
outputSubst = Platform::Path::From(inputFile.FileStem());
|
|
|
|
} else {
|
|
|
|
outputSubst = outputSubst.Join(inputFile.FileStem());
|
|
|
|
}
|
2017-03-11 22:43:21 +08:00
|
|
|
outputFile.raw.replace(replaceAt, 1, outputSubst.raw);
|
2016-11-29 10:57:41 +08:00
|
|
|
}
|
2017-03-11 22:43:21 +08:00
|
|
|
Platform::Path absOutputFile = outputFile.Expand(/*fromCurrentDirectory=*/true);
|
2016-11-29 10:57:41 +08:00
|
|
|
|
|
|
|
SS.Init();
|
2016-12-05 08:25:31 +08:00
|
|
|
if(!SS.LoadFromFile(absInputFile)) {
|
2017-03-11 22:43:21 +08:00
|
|
|
fprintf(stderr, "Cannot load '%s'!\n", inputFile.raw.c_str());
|
2016-11-29 10:57:41 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
SS.AfterNewFile();
|
2016-12-05 08:25:31 +08:00
|
|
|
runner(absOutputFile);
|
2016-11-29 10:57:41 +08:00
|
|
|
SK.Clear();
|
|
|
|
SS.Clear();
|
|
|
|
|
2017-03-11 22:43:21 +08:00
|
|
|
fprintf(stderr, "Written '%s'.\n", outputFile.raw.c_str());
|
2016-11-29 10:57:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
2016-12-05 08:25:31 +08:00
|
|
|
std::vector<std::string> args = InitPlatform(argc, argv);
|
2016-11-29 10:57:41 +08:00
|
|
|
|
2016-12-05 08:25:31 +08:00
|
|
|
if(args.size() == 1) {
|
|
|
|
ShowUsage(args[0]);
|
2016-11-29 10:57:41 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-12-05 08:25:31 +08:00
|
|
|
if(!RunCommand(args)) {
|
2016-11-29 10:57:41 +08:00
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|