1 /************************************************************************
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
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.
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 ************************************************************************/
50 #define IS_WHITESPACE(c) ((c == ' ') || (c == '\t'))
53 fprintf( stderr, "mtxrun: " ); \
54 fprintf( stderr, __VA_ARGS__ ); \
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 ** );
67 int main( int argc
, char *argv
[] )
69 __declspec(dllexport
) int dllrunscript( int argc
, char *argv
[] )
72 char *binary
, *s
, *luatexfname
, *argstr
, **lua_argv
;
73 int k
, quoted
, lua_argc
;
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
89 while ( k
&& (argv
[0][k
-1] != '/') && (argv
[0][k
-1] != '\\') ) k
--;
90 strcpy(progname
, &argv
[0][k
]);
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) {
97 progname
[strlen(progname
) - 3]='\0';
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" );
117 } else if ( strcmpi(progname
,"texmfstart") == 0 ) {
118 strcat( scriptpath
, "mtxrun.lua" );
120 strcat( scriptpath
, "mtxrun.lua" );
123 if ( GetFileAttributes(scriptpath
) == INVALID_FILE_ATTRIBUTES
)
124 DIE( "file not found: %s\n", scriptpath
);
126 // find luatex.exe /luajittex.exe
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");
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) */
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) */
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) */
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) */
202 /* binary = (is_jit ? "texluajit.exe":"texlua.exe"); */
204 /* DIE( "unable to locate texlua.exe on the search path" ); */
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
)
217 DIE( "unable to locate dllluatexmain procedure in luajittex.dll" )
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
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
);
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
, "\"" );
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
273 PROCESS_INFORMATION pi
;
274 ZeroMemory( &si
, 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
) );
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
);
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