beta-0.89.2
[luatex.git] / source / texk / texlive / w32_wrapper / context / mtxrun_dll.c
blobfc2e260f5a25da0f0862bc59790347b48c335dc9
1 /************************************************************************
3 Copyright:
5 Public Domain
6 Originally written in 2010 by Tomasz M. Trzeciak and Hans Hagen
8 This program is derived from the 'runscript' program originally
9 written in 2009 by T.M. Trzeciak. It has been adapted for use in
10 ConTeXt MkIV.
12 Comment:
14 In ConTeXt MkIV we have two core scripts: luatools.lua and
15 mtxrun.lua where the second one is used to launch other scripts.
16 Normally a user will use a call like:
18 mtxrun --script font --reload
20 Here mtxrun is a lua script. In order to avoid the usage of a cmd
21 file on windows this runner will start texlua directly. If the
22 shared library luatex.dll is available, texlua will be started in
23 the same process avoiding thus any additional overhead. Otherwise
24 it will be spawned in a new proces.
26 We also don't want to use other runners, like those that use kpse
27 to locate the script as this is exactly what mtxrun itself is doing
28 already. Therefore the runscript program is adapted to a more direct
29 approach suitable for mtxrun.
31 Compilation:
33 with gcc (size optimized):
35 gcc -Os -s -shared -o mtxrun.dll mtxrun_dll.c
36 gcc -Os -s -o mtxrun.exe mtxrun_exe.c -L./ -lmtxrun
38 with tcc (extra small size):
40 tcc -shared -o mtxrun.dll mtxrun_dll.c
41 tcc -o mtxrun.exe mtxrun_exe.c mtxrun.def
43 ************************************************************************/
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <windows.h>
49 //#define STATIC
50 #define IS_WHITESPACE(c) ((c == ' ') || (c == '\t'))
51 #define MAX_CMD 32768
52 #define DIE(...) { \
53 fprintf( stderr, "mtxrun: " ); \
54 fprintf( stderr, __VA_ARGS__ ); \
55 return 1; \
58 static char cmdline[MAX_CMD];
59 static char dirpath[MAX_PATH];
60 static char progname[MAX_PATH];
61 static char scriptpath[MAX_PATH];
62 static char luatexpath[MAX_PATH];
63 HMODULE dllluatex = NULL;
64 typedef int ( *mainlikeproc )( int, char ** );
66 #ifdef STATIC
67 int main( int argc, char *argv[] )
68 #else
69 __declspec(dllexport) int dllrunscript( int argc, char *argv[] )
70 #endif
72 char *binary, *s, *luatexfname, *argstr, **lua_argv;
73 int k, quoted, lua_argc;
74 int passprogname = 0;
75 unsigned char is_jit=0;
77 // directory of this module/executable
78 HMODULE module_handle = GetModuleHandle( "mtxrun.dll" );
79 // if ( module_handle == NULL ) exe path will be used, which is OK too
80 k = (int) GetModuleFileName( module_handle, dirpath, MAX_PATH );
81 if ( !k || ( k == MAX_PATH ) )
82 DIE( "unable to determine a valid module name\n" );
83 s = strrchr(dirpath, '\\');
84 if ( s == NULL ) DIE( "no directory part in module path: %s\n", dirpath );
85 *(++s) = '\0'; //remove file name, leave trailing backslash
87 // program name
88 k = strlen(argv[0]);
89 while ( k && (argv[0][k-1] != '/') && (argv[0][k-1] != '\\') ) k--;
90 strcpy(progname, &argv[0][k]);
91 s = progname;
92 if ( s = strrchr(s, '.') ) *s = '\0'; // remove file extension part
94 /* check "jit" : strlen("jit") = 3 */
95 if (strncmp(progname + strlen(progname) - 3, "jit", 3) == 0) {
96 is_jit = 1;
97 progname[strlen(progname) - 3]='\0';
99 else
100 is_jit = 0;
102 // script path
104 strcpy( scriptpath, dirpath );
105 k = strlen(progname);
106 if ( k < 6 ) k = 6; // in case the program name is shorter than "mtxrun"
107 if ( strlen(dirpath) + k + 4 >= MAX_PATH )
108 DIE( "path too long: %s%s\n", dirpath, progname );
110 if ( strcmpi(progname,"mtxrun") == 0 ) {
111 strcat( scriptpath, progname );
112 strcat( scriptpath, ".lua" );
113 } else if ( strcmpi(progname,"luatools") == 0 ) {
114 strcat( scriptpath, "mtxrun.lua" );
115 strcpy( progname, "base" );
116 passprogname = 1;
117 } else if ( strcmpi(progname,"texmfstart") == 0 ) {
118 strcat( scriptpath, "mtxrun.lua" );
119 } else {
120 strcat( scriptpath, "mtxrun.lua" );
121 passprogname = 1;
123 if ( GetFileAttributes(scriptpath) == INVALID_FILE_ATTRIBUTES )
124 DIE( "file not found: %s\n", scriptpath );
126 // find luatex.exe /luajittex.exe
127 if ( SearchPath(
128 dirpath, // was getenv( "PATH" ), // path to search (optional)
129 (is_jit ? "luajittex.exe":"luatex.exe"), // file name to search
130 NULL, // file extension to add (optional)
131 MAX_PATH, // output buffer size
132 luatexpath, // output buffer pointer
133 &luatexfname ) // pointer to a file part in the output buffer (optional)
135 binary = (is_jit ? "luajittex.exe":"luatex.exe");
136 } else if ( SearchPath(
137 dirpath, // was getenv( "PATH" ), // path to search (optional)
138 (is_jit ? "texluajit.exe":"texlua.exe"), // file name to search
139 NULL, // file extension to add (optional)
140 MAX_PATH, // output buffer size
141 luatexpath, // output buffer pointer
142 &luatexfname ) // pointer to a file part in the output buffer (optional)
144 binary = (is_jit ? "texluajit.exe":"texlua.exe");
145 } else if ( SearchPath(
146 getenv("PATH"), // was dirpath, // path to search (optional)
147 (is_jit ? "luajittex.exe":"luatex.exe"), // file name to search
148 NULL, // file extension to add (optional)
149 MAX_PATH, // output buffer size
150 luatexpath, // output buffer pointer
151 &luatexfname ) // pointer to a file part in the output buffer (optional)
153 binary = (is_jit ? "luajittex.exe":"luatex.exe");
154 } else if ( SearchPath(
155 getenv("PATH") , // was dirpath, // path to search (optional)
156 (is_jit ? "texluajit.exe":"texlua.exe"), // file name to search
157 NULL, // file extension to add (optional)
158 MAX_PATH, // output buffer size
159 luatexpath, // output buffer pointer
160 &luatexfname ) // pointer to a file part in the output buffer (optional)
162 binary = (is_jit ? "texluajit.exe":"texlua.exe");
163 }else {
164 DIE( "unable to locate texlua.exe on the search path" );
167 /* if ( SearchPath( */
168 /* dirpath, // was getenv( "PATH" ), // path to search (optional) */
169 /* (is_jit ? "luajittex.exe":"luatex.exe"), // file name to search */
170 /* NULL, // file extension to add (optional) */
171 /* MAX_PATH, // output buffer size */
172 /* luatexpath, // output buffer pointer */
173 /* &luatexfname ) // pointer to a file part in the output buffer (optional) */
174 /* ) { */
175 /* binary = (is_jit ? "luajittex.exe":"luatex.exe"); */
176 /* }else if ( SearchPath( */
177 /* getenv("PATH"), // was dirpath, // path to search (optional) */
178 /* (is_jit ? "luajittex.exe":"luatex.exe"), // file name to search */
179 /* NULL, // file extension to add (optional) */
180 /* MAX_PATH, // output buffer size */
181 /* luatexpath, // output buffer pointer */
182 /* &luatexfname ) // pointer to a file part in the output buffer (optional) */
183 /* ) { */
184 /* binary = (is_jit ? "luajittex.exe":"luatex.exe"); */
185 /* }else if ( SearchPath( */
186 /* dirpath, // was getenv( "PATH" ), // path to search (optional) */
187 /* (is_jit ? "texluajit.exe":"texlua.exe"), // file name to search */
188 /* NULL, // file extension to add (optional) */
189 /* MAX_PATH, // output buffer size */
190 /* luatexpath, // output buffer pointer */
191 /* &luatexfname ) // pointer to a file part in the output buffer (optional) */
192 /* ) { */
193 /* binary = (is_jit ? "texluajit.exe":"texlua.exe"); */
194 /* }else if ( SearchPath( */
195 /* getenv("PATH") , // was dirpath, // path to search (optional) */
196 /* (is_jit ? "texluajit.exe":"texlua.exe"), // file name to search */
197 /* NULL, // file extension to add (optional) */
198 /* MAX_PATH, // output buffer size */
199 /* luatexpath, // output buffer pointer */
200 /* &luatexfname ) // pointer to a file part in the output buffer (optional) */
201 /* ) { */
202 /* binary = (is_jit ? "texluajit.exe":"texlua.exe"); */
203 /* }else { */
204 /* DIE( "unable to locate texlua.exe on the search path" ); */
205 /* } */
210 // link directly with luatex.dll if available in texlua's dir
211 strcpy( luatexfname, (is_jit ? "luajittex.dll":"luatex.dll") );
212 if ( dllluatex = LoadLibrary(luatexpath) )
214 mainlikeproc dllluatexmain = (mainlikeproc) GetProcAddress( dllluatex, (is_jit ? "dllluajittexmain": "dllluatexmain" ));
215 if ( dllluatexmain == NULL )
216 if (is_jit)
217 DIE( "unable to locate dllluatexmain procedure in luajittex.dll" )
218 else
219 DIE( "unable to locate dllluatexmain procedure in luatex.dll" );
221 // set up argument list for texlua script
223 lua_argv = (char **)malloc( (argc + 5) * sizeof(char *) );
224 if ( lua_argv == NULL ) DIE( "out of memory\n" );
225 lua_argv[lua_argc=0] = luatexfname;
226 lua_argv[++lua_argc] = "--luaonly";
227 lua_argv[++lua_argc] = scriptpath; // script to execute
228 if (passprogname) {
229 lua_argv[++lua_argc] = "--script";
230 lua_argv[++lua_argc] = progname;
232 for ( k = 1; k < argc; k++ ) lua_argv[++lua_argc] = argv[k];
233 lua_argv[++lua_argc] = NULL;
235 // call texlua interpreter
236 // dllluatexmain never returns, but we pretend that it does
238 k = dllluatexmain( lua_argc, lua_argv );
239 if (lua_argv) free( lua_argv );
240 return k;
242 // we are still here, so no luatex.dll; spawn texlua.exe instead
244 strcpy( luatexfname,binary);
245 strcpy( cmdline, " --luaonly " );
246 strcpy( cmdline, "\"" );
247 strcat( cmdline, luatexpath );
248 strcat( cmdline, "\" \"" );
249 strcat( cmdline, scriptpath );
250 strcat( cmdline, "\"" );
251 if (passprogname) {
252 strcat( cmdline, " --script " );
253 strcat( cmdline, progname );
255 argstr = GetCommandLine(); // get the command line of this process
256 if ( argstr == NULL ) DIE( "unable to retrieve the command line string\n" );
258 // skip over argv[0] in the argument string
259 // (it can contain embedded double quotes if launched from cmd.exe!)
261 for ( quoted = 0; (*argstr) && ( !IS_WHITESPACE(*argstr) || quoted ); argstr++ )
262 if (*argstr == '"') quoted = !quoted;
264 // pass through all the arguments
266 if ( strlen(cmdline) + strlen(argstr) >= MAX_CMD )
267 DIE( "command line string too long:\n%s%s\n", cmdline, argstr );
268 strcat( cmdline, argstr );
270 // create child process
272 STARTUPINFO si;
273 PROCESS_INFORMATION pi;
274 ZeroMemory( &si, sizeof(si) );
275 si.cb = sizeof(si);
276 si.dwFlags = STARTF_USESTDHANDLES;// | STARTF_USESHOWWINDOW;
277 //si.dwFlags = STARTF_USESHOWWINDOW;
278 //si.wShowWindow = SW_HIDE ; // can be used to hide console window (requires STARTF_USESHOWWINDOW flag)
279 si.hStdInput = GetStdHandle( STD_INPUT_HANDLE );
280 si.hStdOutput = GetStdHandle( STD_OUTPUT_HANDLE );
281 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
282 ZeroMemory( &pi, sizeof(pi) );
283 if( !CreateProcess(
284 NULL, // module name (uses command line if NULL)
285 cmdline, // command line
286 NULL, // process security atrributes
287 NULL, // thread security atrributes
288 TRUE, // handle inheritance
289 0, // creation flags, e.g. CREATE_NEW_CONSOLE, CREATE_NO_WINDOW, DETACHED_PROCESS
290 NULL, // pointer to environment block (uses parent if NULL)
291 NULL, // starting directory (uses parent if NULL)
292 &si, // STARTUPINFO structure
293 &pi ) // PROCESS_INFORMATION structure
294 ) DIE( "command execution failed: %s\n", cmdline );
295 DWORD ret = 0;
296 CloseHandle( pi.hThread ); // thread handle is not needed
297 if ( WaitForSingleObject( pi.hProcess, INFINITE ) == WAIT_OBJECT_0 ) {
298 if ( !GetExitCodeProcess( pi.hProcess, &ret) )
299 DIE( "unable to retrieve process exit code: %s\n", cmdline );
300 } else DIE( "failed to wait for process termination: %s\n", cmdline );
301 CloseHandle( pi.hProcess );
303 // propagate exit code from the child process
304 return ret;