1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
/**
* @file scriptcommand.cpp
* @author Nat Goodspeed
* @date 2024-09-16
* @brief Implementation for scriptcommand.
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Copyright (c) 2024, Linden Research, Inc.
* $/LicenseInfo$
*/
// Precompiled header
#include "linden_common.h"
// associated header
#include "scriptcommand.h"
// STL headers
// std headers
#include <sstream>
// external library headers
// other Linden headers
#include "fsyspath.h"
#include "llerror.h"
#include "llsdutil.h"
#include "llstring.h"
#include "stringize.h"
ScriptCommand::ScriptCommand(const std::string& command, const LLSD& path,
const std::string& base)
{
fsyspath basepath(base);
// Use LLStringUtil::getTokens() to parse the script command line
args = LLStringUtil::getTokens(command,
" \t\r\n", // drop_delims
"", // no keep_delims
"\"'", // either kind of quotes
"\\"); // backslash escape
// search for args[0] on paths
if (search(args[0], path, basepath))
{
// The first token is in fact the script filename. Now that we've
// found the script file, we've consumed that token. The rest are
// command-line arguments.
args.erase(args.begin());
return;
}
// Parsing the command line produced a script file path we can't find.
// Maybe that's because there are spaces in the original pathname that
// were neither quoted nor escaped? See if we can find the whole original
// command line string.
if (search(command, path, basepath))
{
// Here we found script, using the whole input command line as its
// pathname. Discard any parts of it we mistook for command-line
// arguments.
args.clear();
return;
}
// Couldn't find the script either way. Is it because we can't even check
// existence?
if (! mError.empty())
{
return;
}
// No, existence check works, we just can't find the script.
std::ostringstream msgstream;
msgstream << "Can't find script file " << std::quoted(args[0]);
if (command != args[0])
{
msgstream << " or " << std::quoted(command);
}
if (path.size() > 0)
{
msgstream << " on " << path;
}
if (! base.empty())
{
msgstream << " relative to " << base;
}
mError = msgstream.str();
LL_WARNS("Lua") << mError << LL_ENDL;
}
bool ScriptCommand::search(const fsyspath& script, const LLSD& paths, const fsyspath& base)
{
for (const auto& path : llsd::inArray(paths))
{
// If a path is already absolute, (otherpath / path) preserves it.
// Explicitly instantiate fsyspath for every string conversion to
// properly convert UTF-8 filename strings on Windows.
fsyspath absscript{ base / fsyspath(path.asString()) / script };
bool exists;
try
{
exists = std::filesystem::exists(absscript);
}
catch (const std::filesystem::filesystem_error& exc)
{
mError = stringize("Can't check existence: ", exc.what());
LL_WARNS("Lua") << mError << LL_ENDL;
return false;
}
if (exists)
{
this->script = absscript.string();
return true;
}
}
return false;
}
std::string ScriptCommand::error() const
{
return mError;
}
|