mirror of
https://github.com/love2d/love-appimage-source.git
synced 2026-08-12 08:40:51 +02:00
237 lines
8.8 KiB
C
237 lines
8.8 KiB
C
/**************************************************************************
|
|
|
|
Copyright (c) 2004-18 Simon Peter
|
|
Portions Copyright (c) 2010 RazZziel
|
|
|
|
All Rights Reserved.
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
|
|
**************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <libgen.h>
|
|
#include <dirent.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#define die(...) \
|
|
do { \
|
|
fprintf(stderr, "Error: " __VA_ARGS__); \
|
|
exit(1); \
|
|
} while(0);
|
|
#define SET_NEW_ENV(str,len,fmt,...) \
|
|
format = fmt; \
|
|
length = strlen(format) + (len); \
|
|
char *str = calloc(length, sizeof(char)); \
|
|
snprintf(str, length, format, __VA_ARGS__); \
|
|
putenv(str);
|
|
#define MAX(a,b) (a > b ? a : b)
|
|
#define bool int
|
|
#define false 0
|
|
#define true -1
|
|
|
|
#define LINE_SIZE 255
|
|
|
|
int filter(const struct dirent *dir) {
|
|
char *p = (char*) &dir->d_name;
|
|
p = strrchr(p, '.');
|
|
return p && !strcmp(p, ".desktop");
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
char *appdir = dirname(realpath("/proc/self/exe", NULL));
|
|
if (!appdir)
|
|
die("Could not access /proc/self/exe\n");
|
|
|
|
int ret;
|
|
struct dirent **namelist;
|
|
ret = scandir(appdir, &namelist, filter, NULL);
|
|
|
|
if (ret == 0) {
|
|
die("No .desktop files found\n");
|
|
} else if(ret == -1) {
|
|
die("Could not scan directory %s\n", appdir);
|
|
}
|
|
|
|
/* Extract executable from .desktop file */
|
|
char *desktop_file = calloc(LINE_SIZE, sizeof(char));
|
|
snprintf(desktop_file, LINE_SIZE, "%s/%s", appdir, namelist[0]->d_name);
|
|
FILE *f = fopen(desktop_file, "r");
|
|
char *line = malloc(LINE_SIZE);
|
|
size_t n = LINE_SIZE;
|
|
|
|
do {
|
|
if (getline(&line, &n, f) == -1)
|
|
die("Executable not found, make sure there is a line starting with 'Exec='\n");
|
|
} while(strncmp(line, "Exec=", 5));
|
|
fclose(f);
|
|
char *exe = line+5;
|
|
|
|
// parse arguments
|
|
bool in_quotes = 0;
|
|
for (n = 0; n < LINE_SIZE; n++) {
|
|
if (!line[n]) // end of string
|
|
break;
|
|
else if (line[n] == 10 || line[n] == 13) {
|
|
line[n] = '\0';
|
|
line[n+1] = '\0';
|
|
line[n+2] = '\0';
|
|
break;
|
|
} else if (line[n] == '"') {
|
|
in_quotes = !in_quotes;
|
|
} else if (line[n] == ' ' && !in_quotes)
|
|
line[n] = '\0';
|
|
}
|
|
|
|
// count arguments
|
|
char* arg = exe;
|
|
int argcount = 0;
|
|
while ((arg += (strlen(arg)+1)) && *arg)
|
|
argcount += 1;
|
|
|
|
// merge args
|
|
char* outargptrs[argcount + argc + 1];
|
|
outargptrs[0] = exe;
|
|
int outargindex = 1;
|
|
arg = exe;
|
|
int argc_ = argc - 1; // argv[0] is the filename
|
|
char** argv_ = argv + 1;
|
|
while ((arg += (strlen(arg)+1)) && *arg) {
|
|
if (arg[0] == '%' || (arg[0] == '"' && arg[1] == '%')) { // handle desktop file field codes
|
|
char code = arg[arg[0] == '%' ? 1 : 2];
|
|
switch(code) {
|
|
case 'f':
|
|
case 'u':
|
|
if (argc_ > 0) {
|
|
outargptrs[outargindex++] = *argv_++;
|
|
argc_--;
|
|
}
|
|
break;
|
|
case 'F':
|
|
case 'U':
|
|
while (argc_ > 0) {
|
|
outargptrs[outargindex++] = *argv_++;
|
|
argc_--;
|
|
}
|
|
break;
|
|
case 'i':
|
|
case 'c':
|
|
case 'k':
|
|
fprintf(stderr, "WARNING: Desktop file field code %%%c is not currently supported\n", code);
|
|
break;
|
|
default:
|
|
fprintf(stderr, "WARNING: Invalid desktop file field code %%%c\n", code);
|
|
break;
|
|
}
|
|
} else {
|
|
outargptrs[outargindex++] = arg;
|
|
}
|
|
}
|
|
while (argc_ > 0) {
|
|
outargptrs[outargindex++] = *argv_++;
|
|
argc_--;
|
|
}
|
|
outargptrs[outargindex] = '\0'; // trailing null argument required by execvp()
|
|
|
|
// change directory
|
|
size_t appdir_s = strlen(appdir);
|
|
char *usr_in_appdir = malloc(appdir_s + 5);
|
|
/*
|
|
snprintf(usr_in_appdir, appdir_s + 5, "%s/usr", appdir);
|
|
ret = chdir(usr_in_appdir);
|
|
if (ret != 0)
|
|
die("Could not cd into %s\n", usr_in_appdir);
|
|
*/
|
|
|
|
// set environment variables
|
|
char *old_env;
|
|
size_t length;
|
|
const char *format;
|
|
|
|
/* https://docs.python.org/2/using/cmdline.html#envvar-PYTHONHOME */
|
|
SET_NEW_ENV(new_pythonhome, appdir_s, "PYTHONHOME=%s/", appdir);
|
|
|
|
old_env = getenv("PATH") ?: "";
|
|
SET_NEW_ENV(new_path, appdir_s + strlen(old_env), "PATH=%s/bin/:%s", appdir, old_env);
|
|
|
|
old_env = getenv("LD_LIBRARY_PATH") ?: "";
|
|
SET_NEW_ENV(new_ld_library_path, appdir_s + strlen(old_env), "LD_LIBRARY_PATH=%s/lib/:%s", appdir, old_env);
|
|
|
|
old_env = getenv("PYTHONPATH") ?: "";
|
|
SET_NEW_ENV(new_pythonpath, appdir_s + strlen(old_env), "PYTHONPATH=%s/share/pyshared/:%s", appdir, old_env);
|
|
|
|
old_env = getenv("XDG_DATA_DIRS") ?: "/usr/local/share/:/usr/share/";
|
|
SET_NEW_ENV(new_xdg_data_dirs, appdir_s + strlen(old_env), "XDG_DATA_DIRS=%s/share/:%s", appdir, old_env);
|
|
|
|
old_env = getenv("PERLLIB") ?: "";
|
|
SET_NEW_ENV(new_perllib, appdir_s*2 + strlen(old_env), "PERLLIB=%s/share/perl5/:%s/lib/perl5/:%s", appdir, appdir, old_env);
|
|
|
|
/* http://askubuntu.com/questions/251712/how-can-i-install-a-gsettings-schema-without-root-privileges */
|
|
old_env = getenv("GSETTINGS_SCHEMA_DIR") ?: "";
|
|
SET_NEW_ENV(new_gsettings_schema_dir, appdir_s + strlen(old_env), "GSETTINGS_SCHEMA_DIR=%s/share/glib-2.0/schemas/:%s", appdir, old_env);
|
|
|
|
old_env = getenv("QT_PLUGIN_PATH") ?: "";
|
|
SET_NEW_ENV(new_qt_plugin_path, appdir_s*10 + strlen(old_env), "QT_PLUGIN_PATH=%s/lib/qt4/plugins/:%s/lib/i386-linux-gnu/qt4/plugins/:%s/lib/x86_64-linux-gnu/qt4/plugins/:%s/lib32/qt4/plugins/:%s/lib64/qt4/plugins/:%s/lib/qt5/plugins/:%s/lib/i386-linux-gnu/qt5/plugins/:%s/lib/x86_64-linux-gnu/qt5/plugins/:%s/lib32/qt5/plugins/:%s/lib64/qt5/plugins/:%s", appdir, appdir, appdir, appdir, appdir, appdir, appdir, appdir, appdir, appdir, old_env);
|
|
|
|
SET_NEW_ENV(new_gspath, appdir_s + strlen(old_env), "GST_PLUGIN_SYSTEM_PATH=%s/lib/gstreamer:%s", appdir, old_env);
|
|
SET_NEW_ENV(new_gspath1, appdir_s + strlen(old_env), "GST_PLUGIN_SYSTEM_PATH_1_0=%s/lib/gstreamer-1.0:%s", appdir, old_env);
|
|
|
|
/* Otherwise may get errors because Python cannot write __pycache__ bytecode cache */
|
|
putenv("PYTHONDONTWRITEBYTECODE=1");
|
|
|
|
/* Lua-specific stuff by MikuAuahDark */
|
|
old_env = getenv("LUA_PATH");
|
|
if (old_env) {
|
|
SET_NEW_ENV(new_lua_path, appdir_s*2 + strlen(old_env), "LUA_PATH=%s;%s/share/luajit-2.1.0-beta3/?.lua;%s/share/lua/5.1/?.lua;;", old_env, appdir, appdir);
|
|
} else {
|
|
SET_NEW_ENV(new_lua_path, appdir_s*2, "LUA_PATH=%s/share/luajit-2.1.0-beta3/?.lua;%s/share/lua/5.1/?.lua;;", appdir, appdir);
|
|
}
|
|
|
|
old_env = getenv("LUA_CPATH");
|
|
if (old_env) {
|
|
SET_NEW_ENV(new_lua_cpath, appdir_s + strlen(old_env), "LUA_CPATH=%s;=%s/lib/lua/5.1/?.so;;", old_env, appdir);
|
|
} else {
|
|
SET_NEW_ENV(new_lua_cpath, appdir_s, "LUA_CPATH=%s/lib/lua/5.1/?.so;;", appdir);
|
|
}
|
|
|
|
/* Run */
|
|
ret = execvp(exe, outargptrs);
|
|
|
|
int error = errno;
|
|
|
|
if (ret == -1)
|
|
die("Error executing '%s': %s\n", exe, strerror(error));
|
|
|
|
free(line);
|
|
free(desktop_file);
|
|
free(usr_in_appdir);
|
|
free(new_pythonhome);
|
|
free(new_path);
|
|
free(new_ld_library_path);
|
|
free(new_pythonpath);
|
|
free(new_xdg_data_dirs);
|
|
free(new_perllib);
|
|
free(new_gsettings_schema_dir);
|
|
free(new_qt_plugin_path);
|
|
return 0;
|
|
}
|