aboutsummaryrefslogtreecommitdiffstats
path: root/src/args.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/args.c')
-rw-r--r--src/args.c206
1 files changed, 206 insertions, 0 deletions
diff --git a/src/args.c b/src/args.c
new file mode 100644
index 0000000..7b307a8
--- /dev/null
+++ b/src/args.c
@@ -0,0 +1,206 @@
+#include "args.h"
+#include "l2su.h"
+#include "instance.h"
+#include "version.h"
+#include "macros.h"
+
+#include <jansson.h>
+#include <stdarg.h>
+#include <string.h>
+
+int l2_args__get_game_args(l2_subst_t *subst, const char *argsline, l2_version_feature_match_proc_t *feature_matcher, char ***out_args, size_t *out_nargs);
+int l2_args__get_args_json(l2_subst_t *subst, json_t *jargs, l2_version_feature_match_proc_t *feature_matcher, char ***out_args, size_t *out_nargs);
+
+int l2_args_get_game_args(json_t *version, l2_subst_t *subst, l2_version_feature_match_proc_t *feature_matcher, char ***out_args, size_t *out_nargs)
+{
+ const char *mc_args = NULL;
+ json_t *jargs = NULL;
+
+ if (json_unpack(version, "{s?:{s:o}, s?:s}", "arguments", "game", &jargs, "minecraftArguments", &mc_args) < 0) {
+ return -1;
+ }
+
+ if (jargs) {
+ if (!json_is_array(jargs)) return -1;
+
+
+ return l2_args__get_args_json(subst, jargs, feature_matcher, out_args, out_nargs);
+ } else if (mc_args) {
+ return l2_args__get_game_args(subst, mc_args, feature_matcher, out_args, out_nargs);
+ } else {
+ return -1;
+ }
+}
+
+int L2_SENTINEL l2_args__array_append(l2_subst_t *sp, char ***arr, size_t *nargs, ...)
+{
+ size_t nadd = 0;
+ const char *to_add;
+
+ va_list parg;
+ va_start(parg, nargs);
+ do {
+ to_add = va_arg(parg, const char *);
+ ++nadd;
+ } while (to_add);
+ --nadd;
+ va_end(parg);
+
+ char **temp = realloc(*arr, (*nargs + nadd) * sizeof(char *));
+ if (!temp) return -1;
+ *arr = temp;
+
+ memset(temp + *nargs, 0, sizeof(char *) * nadd);
+
+ va_start(parg, nargs);
+
+ for (; nadd; --nadd) {
+ if (l2_subst_apply(sp, va_arg(parg, const char *), temp + (*nargs)++) < 0) goto cleanup;
+ }
+
+ va_end(parg);
+ return 0;
+
+cleanup:
+ va_end(parg);
+ return -1;
+}
+
+int l2_args__get_game_args(l2_subst_t *subst, const char *argsline, l2_version_feature_match_proc_t *feature_matcher, char ***out_args, size_t *out_nargs)
+{
+ char **args = NULL;
+ size_t nargs = 0;
+
+ char *arg_start;
+ size_t sz;
+ L2_ASTRDUP(arg_start, sz, argsline);
+
+ for (char *argcur = arg_start; *argcur; ++argcur) {
+ if (*argcur == ' ') {
+ *argcur = '\0';
+ if (l2_args__array_append(subst, &args, &nargs, arg_start, NULL) < 0) goto cleanup;
+ arg_start = argcur + 1;
+ }
+ }
+
+ if (*arg_start && l2_args__array_append(subst, &args, &nargs, arg_start, NULL) < 0) goto cleanup;
+
+ if ((*feature_matcher)("is_demo_user", json_true())) {
+ if (l2_args__array_append(subst, &args, &nargs, "--demo", NULL) < 0) goto cleanup;
+ }
+
+ if ((*feature_matcher)("has_custom_resolution", json_true())) {
+ if (l2_args__array_append(subst, &args, &nargs, "--width", "${resolution_width}", "--height", "${resolution_height}", NULL) < 0) goto cleanup;
+ }
+
+ *out_args = args;
+ *out_nargs = nargs;
+ return 0;
+
+cleanup:
+ for (char **cur = args; nargs; --nargs, ++cur) {
+ free(*cur);
+ }
+
+ free(args);
+
+ return -1;
+}
+
+int l2_args_get_jvm_args(json_t *version, l2_subst_t *subst, l2_version_feature_match_proc_t *feature_matcher, char ***out_args, size_t *out_nargs)
+{
+ json_t *jarguments = json_object_get(version, "arguments");
+ if (!jarguments) {
+ char **args = NULL;
+ size_t nargs = 0;
+
+ if (l2_args__array_append(subst, &args, &nargs,
+#ifdef L2SU_LAUNCHER_IS_WINDOWS
+ "-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump",
+#endif
+#ifdef L2SU_LAUNCHER_IS_OSX
+ "-Xdock:icon=${asset=icons/minecraft.icns}",
+ "-Xdock:name=Minecraft",
+#endif
+ "-Djava.library.path=${natives_directory}",
+ "-Dminecraft.launcher.brand=${launcher_name}",
+ "-Dminecraft.launcher.version=${launcher_version}",
+ "-Dminecraft.client.jar=${primary_jar}",
+ "-cp",
+ "${classpath}",
+ NULL) < 0) {
+ return -1;
+ }
+
+ *out_args = args;
+ *out_nargs = nargs;
+
+ return 0;
+ } else if (!json_is_object(jarguments)) {
+ return -1;
+ }
+
+ json_t *jjvmargs = json_object_get(jarguments, "jvm");
+ if (!json_is_array(jjvmargs)) {
+ return -1;
+ }
+
+ return l2_args__get_args_json(subst, jjvmargs, feature_matcher, out_args, out_nargs);
+}
+
+int l2_args__get_args_json(l2_subst_t *subst, json_t *jargs, l2_version_feature_match_proc_t *feature_matcher, char ***out_args, size_t *out_nargs)
+{
+ char **args = NULL;
+ size_t nargs = 0;
+
+ size_t idx;
+ json_t *value;
+
+ json_array_foreach(jargs, idx, value) {
+ if (json_is_string(value)) {
+ if (l2_args__array_append(subst, &args, &nargs, json_string_value(value), NULL) < 0) goto cleanup;
+ } else if (json_is_object(value)) {
+ json_t *rules;
+ json_t *values;
+ if (json_unpack(value, "{s:o, s:o}", "rules", &rules, "value", &values) < 0) {
+ goto cleanup;
+ }
+
+ if (!json_is_array(rules)) goto cleanup;
+
+ switch (l2_version_check_rules(rules, feature_matcher)) {
+ case RULE_CHECK_ALLOW: {
+ json_t *argval;
+ size_t argidx;
+ if (json_is_string(values)) {
+ if (l2_args__array_append(subst, &args, &nargs, json_string_value(values), NULL) < 0) goto cleanup;
+ } else {
+ /* this code strongly prefers brevity over performance (breaking news) */
+ json_array_foreach(values, argidx, argval) {
+ if (!json_is_string(argval)) goto cleanup;
+ if (l2_args__array_append(subst, &args, &nargs, json_string_value(argval), NULL) < 0) goto cleanup;
+ }
+ }
+ break;
+ }
+ case RULE_CHECK_ERROR:
+ goto cleanup;
+ default:
+ continue;
+ }
+ }
+ }
+
+ *out_args = args;
+ *out_nargs = nargs;
+ return 0;
+
+cleanup:
+ for (char **cur = args; nargs; --nargs, ++cur) {
+ free(*cur);
+ }
+
+ free(args);
+
+ return -1;
+}