1// 2// Copyright(C) 2005-2014 Simon Howard 3// 4// This program is free software; you can redistribute it and/or 5// modify it under the terms of the GNU General Public License 6// as published by the Free Software Foundation; either version 2 7// of the License, or (at your option) any later version. 8// 9// This program is distributed in the hope that it will be useful, 10// but WITHOUT ANY WARRANTY; without even the implied warranty of 11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12// GNU General Public License for more details. 13// 14 15#include <stdio.h> 16#include <stdlib.h> 17#include <string.h> 18#include <unistd.h> 19#include <sys/stat.h> 20#include <sys/types.h> 21#include <sys/wait.h> 22 23#include <AppKit/AppKit.h> 24 25#include "config.h" 26 27#define RESPONSE_FILE "/tmp/launcher.rsp" 28#define TEMP_SCRIPT "/tmp/tempscript.sh" 29#define WINDOW_TITLE PACKAGE_STRING " command prompt" 30 31static char *executable_path; 32 33// Called on startup to save the location of the launcher program 34// (within a package, other executables should be in the same directory) 35 36void SetProgramLocation(const char *path) 37{ 38 char *p; 39 40 executable_path = strdup(path); 41 42 p = strrchr(executable_path, '/'); 43 *p = '\0'; 44} 45 46// Write out the response file containing command line arguments. 47 48static void WriteResponseFile(const char *iwad, const char *args) 49{ 50 FILE *fstream; 51 52 fstream = fopen(RESPONSE_FILE, "w"); 53 54 if (iwad != NULL) 55 { 56 fprintf(fstream, "-iwad \"%s\"", iwad); 57 } 58 59 if (args != NULL) 60 { 61 fprintf(fstream, "%s", args); 62 } 63 64 fclose(fstream); 65} 66 67static void DoExec(const char *executable, const char *iwad, const char *args) 68{ 69 char *argv[3]; 70 71 asprintf(&argv[0], "%s/%s", executable_path, executable); 72 73 if (iwad != NULL || args != NULL) 74 { 75 WriteResponseFile(iwad, args); 76 77 argv[1] = "@" RESPONSE_FILE; 78 argv[2] = NULL; 79 } 80 else 81 { 82 argv[1] = NULL; 83 } 84 85 execv(argv[0], argv); 86 exit(-1); 87} 88 89// Execute the specified executable contained in the same directory 90// as the launcher, with the specified arguments. 91 92void ExecuteProgram(const char *executable, const char *iwad, const char *args) 93{ 94 pid_t childpid; 95 char *homedir; 96 97 childpid = fork(); 98 99 if (childpid == 0) 100 { 101 signal(SIGCHLD, SIG_DFL); 102 103 // Change directory to home dir before launch, so that any demos 104 // are saved somewhere sensible. 105 106 homedir = getenv("HOME"); 107 108 if (homedir != NULL) 109 { 110 chdir(homedir); 111 } 112 113 DoExec(executable, iwad, args); 114 } 115 else 116 { 117 signal(SIGCHLD, SIG_IGN); 118 } 119} 120 121// Write a sequence of commands that will display the specified message 122// via shell commands. 123 124static void WriteMessage(FILE *script, char *msg) 125{ 126 char *p; 127 128 fprintf(script, "echo \""); 129 130 for (p=msg; *p != '\0'; ++p) 131 { 132 // Start new line? 133 134 if (*p == '\n') 135 { 136 fprintf(script, "\"\necho \""); 137 continue; 138 } 139 140 // Escaped character? 141 142 if (*p == '\\' || *p == '\"') 143 { 144 fprintf(script, "\\"); 145 } 146 147 fprintf(script, "%c", *p); 148 } 149 150 fprintf(script, "\"\n"); 151} 152 153// Open a terminal window with the PATH set appropriately, and DOOMWADPATH 154// set to the specified value. 155 156void OpenTerminalWindow(const char *doomwadpath) 157{ 158 FILE *stream; 159 160 // Generate a shell script that sets the PATH to include the location 161 // where the Doom binaries are, and DOOMWADPATH to include the 162 // IWAD files that have been configured in the launcher interface. 163 // The script then deletes itself and starts a shell. 164 165 stream = fopen(TEMP_SCRIPT, "w"); 166 167 fprintf(stream, "#!/bin/sh\n"); 168 //fprintf(stream, "set -x\n"); 169 fprintf(stream, "PATH=\"%s:$PATH\"\n", executable_path); 170 171 // MANPATH is set to point to the directory within the bundle that 172 // contains the Unix manpages. However, the bundle name or path to 173 // it can contain a space, and OS X doesn't like this! As a 174 // workaround, create a symlink in /tmp to point to the real directory, 175 // and put *this* in MANPATH. 176 177 fprintf(stream, "rm -f \"/tmp/%s.man\"\n", PACKAGE_TARNAME); 178 fprintf(stream, "ln -s \"%s/man\" \"/tmp/%s.man\"\n", 179 executable_path, PACKAGE_TARNAME); 180 fprintf(stream, "MANPATH=\"/tmp/%s.man:$(manpath)\"\n", PACKAGE_TARNAME); 181 fprintf(stream, "export MANPATH\n"); 182 183 fprintf(stream, "DOOMWADPATH=\"%s\"\n", doomwadpath); 184 fprintf(stream, "export DOOMWADPATH\n"); 185 fprintf(stream, "rm -f \"%s\"\n", TEMP_SCRIPT); 186 187 // Window title to something more interesting than "tempscript": 188 fprintf(stream, "echo -en \"\\033]0;%s\\a\"\n", WINDOW_TITLE); 189 190 // Display a useful message: 191 192 fprintf(stream, "clear\n"); 193 WriteMessage(stream, 194 "\n" 195 "This command line has the PATH variable configured so that you may\n" 196 "launch the game with whatever parameters you desire.\n" 197 "\n" 198 "For example:\n" 199 "\n" 200 " " PACKAGE_TARNAME " -iwad doom2.wad -file sid.wad -warp 1\n" 201 "\n" 202 "Type 'exit' to exit.\n"); 203 204 fprintf(stream, "exec $SHELL\n"); 205 fprintf(stream, "\n"); 206 207 fclose(stream); 208 209 chmod(TEMP_SCRIPT, 0755); 210 211 // Tell the terminal to open a window to run the script. 212 213 [[NSWorkspace sharedWorkspace] openFile: @TEMP_SCRIPT 214 withApplication: @"Terminal"]; 215} 216 217void OpenDocumentation(const char *filename) 218{ 219 NSString *path; 220 221 path = [NSString stringWithFormat: @"%s/Documentation/%s", 222 executable_path, filename]; 223 224 [[NSWorkspace sharedWorkspace] openFile: path]; 225} 226 227