1996-09-06 09:51:56 -07:00
|
|
|
/***********************************************************************/
|
|
|
|
/* */
|
|
|
|
/* Objective Caml */
|
|
|
|
/* */
|
|
|
|
/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
|
|
|
|
/* */
|
|
|
|
/* Copyright 1996 Institut National de Recherche en Informatique et */
|
1999-11-17 10:59:06 -08:00
|
|
|
/* en Automatique. All rights reserved. This file is distributed */
|
2001-12-07 05:41:02 -08:00
|
|
|
/* under the terms of the GNU Library General Public License, with */
|
|
|
|
/* the special exception on linking described in file ../LICENSE. */
|
1996-09-06 09:51:56 -07:00
|
|
|
/* */
|
|
|
|
/***********************************************************************/
|
|
|
|
|
|
|
|
/* $Id$ */
|
|
|
|
|
2000-04-04 06:19:12 -07:00
|
|
|
/* Win32-specific stuff */
|
1996-09-06 09:51:56 -07:00
|
|
|
|
2000-04-04 06:19:12 -07:00
|
|
|
#include <windows.h>
|
1996-09-06 09:51:56 -07:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <io.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <ctype.h>
|
2003-03-24 07:25:13 -08:00
|
|
|
#include <errno.h>
|
1996-09-06 09:51:56 -07:00
|
|
|
#include <string.h>
|
2000-04-04 06:19:12 -07:00
|
|
|
#include <signal.h>
|
2001-08-28 07:47:48 -07:00
|
|
|
#include "memory.h"
|
|
|
|
#include "misc.h"
|
|
|
|
#include "osdeps.h"
|
2000-04-04 06:19:12 -07:00
|
|
|
#include "signals.h"
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
#ifndef S_ISREG
|
|
|
|
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
|
|
|
|
#endif
|
|
|
|
|
2004-01-01 08:42:43 -08:00
|
|
|
char * caml_decompose_path(struct ext_table * tbl, char * path)
|
2001-08-28 07:47:48 -07:00
|
|
|
{
|
|
|
|
char * p, * q;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
if (path == NULL) return NULL;
|
2003-12-31 06:20:40 -08:00
|
|
|
p = caml_stat_alloc(strlen(path) + 1);
|
2001-08-28 07:47:48 -07:00
|
|
|
strcpy(p, path);
|
|
|
|
q = p;
|
|
|
|
while (1) {
|
|
|
|
for (n = 0; q[n] != 0 && q[n] != ';'; n++) /*nothing*/;
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_ext_table_add(tbl, q);
|
2001-08-28 07:47:48 -07:00
|
|
|
q = q + n;
|
|
|
|
if (*q == 0) break;
|
|
|
|
*q = 0;
|
|
|
|
q += 1;
|
|
|
|
}
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2004-01-01 08:42:43 -08:00
|
|
|
char * caml_search_in_path(struct ext_table * path, char * name)
|
2001-08-28 07:47:48 -07:00
|
|
|
{
|
|
|
|
char * p, * fullname;
|
|
|
|
int i;
|
|
|
|
struct stat st;
|
2000-04-04 06:19:12 -07:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
for (p = name; *p != 0; p++) {
|
|
|
|
if (*p == '/' || *p == '\\') goto not_found;
|
|
|
|
}
|
|
|
|
for (i = 0; i < path->size; i++) {
|
2003-12-31 06:20:40 -08:00
|
|
|
fullname = caml_stat_alloc(strlen((char *)(path->contents[i])) +
|
|
|
|
strlen(name) + 2);
|
2001-08-28 07:47:48 -07:00
|
|
|
strcpy(fullname, (char *)(path->contents[i]));
|
|
|
|
strcat(fullname, "\\");
|
|
|
|
strcat(fullname, name);
|
2005-09-22 07:21:50 -07:00
|
|
|
caml_gc_message(0x100, "Searching %s\n", (uintnat) fullname);
|
2001-08-28 07:47:48 -07:00
|
|
|
if (stat(fullname, &st) == 0 && S_ISREG(st.st_mode)) return fullname;
|
2003-12-31 06:20:40 -08:00
|
|
|
caml_stat_free(fullname);
|
2001-08-28 07:47:48 -07:00
|
|
|
}
|
|
|
|
not_found:
|
2005-09-22 07:21:50 -07:00
|
|
|
caml_gc_message(0x100, "%s not found in search path\n", (uintnat) name);
|
2003-12-31 06:20:40 -08:00
|
|
|
fullname = caml_stat_alloc(strlen(name) + 1);
|
2001-08-28 07:47:48 -07:00
|
|
|
strcpy(fullname, name);
|
|
|
|
return fullname;
|
|
|
|
}
|
|
|
|
|
2004-01-01 08:42:43 -08:00
|
|
|
CAMLexport char * caml_search_exe_in_path(char * name)
|
2000-04-04 06:19:12 -07:00
|
|
|
{
|
2004-11-24 16:06:06 -08:00
|
|
|
char * fullname, * filepart;
|
|
|
|
DWORD pathlen, retcode;
|
2000-04-04 06:19:12 -07:00
|
|
|
|
2004-11-24 16:06:06 -08:00
|
|
|
pathlen = strlen(name) + 1;
|
|
|
|
if (pathlen < 256) pathlen = 256;
|
|
|
|
while (1) {
|
|
|
|
fullname = stat_alloc(pathlen);
|
|
|
|
retcode = SearchPath(NULL, /* use system search path */
|
|
|
|
name,
|
|
|
|
".exe", /* add .exe extension if needed */
|
|
|
|
pathlen,
|
|
|
|
fullname,
|
|
|
|
&filepart);
|
|
|
|
if (retcode == 0) {
|
|
|
|
caml_gc_message(0x100, "%s not found in search path\n",
|
2005-09-22 07:21:50 -07:00
|
|
|
(uintnat) name);
|
2004-11-24 16:06:06 -08:00
|
|
|
strcpy(fullname, name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (retcode < pathlen) break;
|
|
|
|
stat_free(fullname);
|
|
|
|
pathlen = retcode + 1;
|
|
|
|
}
|
2001-08-28 07:47:48 -07:00
|
|
|
return fullname;
|
|
|
|
}
|
|
|
|
|
2004-01-01 08:42:43 -08:00
|
|
|
char * caml_search_dll_in_path(struct ext_table * path, char * name)
|
2001-08-28 07:47:48 -07:00
|
|
|
{
|
2003-12-31 06:20:40 -08:00
|
|
|
char * dllname = caml_stat_alloc(strlen(name) + 5);
|
2001-08-28 07:47:48 -07:00
|
|
|
char * res;
|
|
|
|
strcpy(dllname, name);
|
|
|
|
strcat(dllname, ".dll");
|
2004-01-01 08:42:43 -08:00
|
|
|
res = caml_search_in_path(path, dllname);
|
2003-12-31 06:20:40 -08:00
|
|
|
caml_stat_free(dllname);
|
2001-08-28 07:47:48 -07:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2006-09-28 14:36:38 -07:00
|
|
|
void * caml_dlopen(char * libname, int for_execution)
|
2001-08-28 07:47:48 -07:00
|
|
|
{
|
2006-09-28 14:36:38 -07:00
|
|
|
HMODULE m;
|
|
|
|
m = LoadLibraryEx(libname, NULL,
|
|
|
|
for_execution ? 0 : DONT_RESOLVE_DLL_REFERENCES);
|
2006-10-03 04:52:40 -07:00
|
|
|
/* Under Win 95/98/ME, LoadLibraryEx can fail in cases where LoadLibrary
|
2006-09-28 14:36:38 -07:00
|
|
|
would succeed. Just try again with LoadLibrary for good measure. */
|
|
|
|
if (m == NULL) m = LoadLibrary(libname);
|
|
|
|
return (void *) m;
|
2001-08-28 07:47:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void caml_dlclose(void * handle)
|
|
|
|
{
|
|
|
|
FreeLibrary((HMODULE) handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
void * caml_dlsym(void * handle, char * name)
|
|
|
|
{
|
|
|
|
return (void *) GetProcAddress((HMODULE) handle, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
char * caml_dlerror(void)
|
|
|
|
{
|
|
|
|
static char dlerror_buffer[256];
|
|
|
|
DWORD msglen =
|
|
|
|
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
NULL, /* message source */
|
|
|
|
GetLastError(), /* error number */
|
|
|
|
0, /* default language */
|
|
|
|
dlerror_buffer, /* destination */
|
|
|
|
sizeof(dlerror_buffer), /* size of destination */
|
|
|
|
NULL); /* no inserts */
|
|
|
|
if (msglen == 0)
|
|
|
|
return "unknown error";
|
2000-04-04 06:19:12 -07:00
|
|
|
else
|
2001-08-28 07:47:48 -07:00
|
|
|
return dlerror_buffer;
|
2000-04-04 06:19:12 -07:00
|
|
|
}
|
|
|
|
|
2001-11-05 08:10:12 -08:00
|
|
|
/* Proper emulation of signal(), including ctrl-C and ctrl-break */
|
|
|
|
|
|
|
|
typedef void (*sighandler)(int sig);
|
|
|
|
static int ctrl_handler_installed = 0;
|
|
|
|
static volatile sighandler ctrl_handler_action = SIG_DFL;
|
|
|
|
|
|
|
|
static BOOL WINAPI ctrl_handler(DWORD event)
|
|
|
|
{
|
|
|
|
int saved_mode;
|
|
|
|
|
|
|
|
/* Only ctrl-C and ctrl-Break are handled */
|
|
|
|
if (event != CTRL_C_EVENT && event != CTRL_BREAK_EVENT) return FALSE;
|
|
|
|
/* Default behavior is to exit, which we get by not handling the event */
|
|
|
|
if (ctrl_handler_action == SIG_DFL) return FALSE;
|
|
|
|
/* Ignore behavior is to do nothing, which we get by claiming that we
|
|
|
|
have handled the event */
|
|
|
|
if (ctrl_handler_action == SIG_IGN) return TRUE;
|
2005-10-12 05:33:47 -07:00
|
|
|
/* Win32 doesn't like it when we do a longjmp() at this point
|
|
|
|
(it looks like we're running in a different thread than
|
|
|
|
the main program!). So, just record the signal. */
|
|
|
|
caml_record_signal(SIGINT);
|
2001-11-05 08:10:12 -08:00
|
|
|
/* We have handled the event */
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2004-01-01 08:42:43 -08:00
|
|
|
sighandler caml_win32_signal(int sig, sighandler action)
|
2001-11-05 08:10:12 -08:00
|
|
|
{
|
|
|
|
sighandler oldaction;
|
|
|
|
|
|
|
|
if (sig != SIGINT) return signal(sig, action);
|
|
|
|
if (! ctrl_handler_installed) {
|
|
|
|
SetConsoleCtrlHandler(ctrl_handler, TRUE);
|
|
|
|
ctrl_handler_installed = 1;
|
|
|
|
}
|
|
|
|
oldaction = ctrl_handler_action;
|
|
|
|
ctrl_handler_action = action;
|
|
|
|
return oldaction;
|
|
|
|
}
|
|
|
|
|
2000-04-04 06:19:12 -07:00
|
|
|
/* Expansion of @responsefile and *? file patterns in the command line */
|
1996-09-06 09:51:56 -07:00
|
|
|
|
|
|
|
static int argc;
|
|
|
|
static char ** argv;
|
|
|
|
static int argvsize;
|
|
|
|
|
1997-09-02 05:55:01 -07:00
|
|
|
static void store_argument(char * arg);
|
|
|
|
static void expand_argument(char * arg);
|
|
|
|
static void expand_pattern(char * arg);
|
|
|
|
static void expand_diversion(char * filename);
|
1996-09-06 09:51:56 -07:00
|
|
|
|
1997-09-02 05:55:01 -07:00
|
|
|
static void out_of_memory(void)
|
1996-09-06 09:51:56 -07:00
|
|
|
{
|
|
|
|
fprintf(stderr, "Out of memory while expanding command line\n");
|
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
|
1997-09-02 05:55:01 -07:00
|
|
|
static void store_argument(char * arg)
|
1996-09-06 09:51:56 -07:00
|
|
|
{
|
|
|
|
if (argc + 1 >= argvsize) {
|
|
|
|
argvsize *= 2;
|
|
|
|
argv = (char **) realloc(argv, argvsize * sizeof(char *));
|
1999-10-14 06:35:40 -07:00
|
|
|
if (argv == NULL) out_of_memory();
|
1996-09-06 09:51:56 -07:00
|
|
|
}
|
|
|
|
argv[argc++] = arg;
|
|
|
|
}
|
|
|
|
|
1997-09-02 05:55:01 -07:00
|
|
|
static void expand_argument(char * arg)
|
1996-09-06 09:51:56 -07:00
|
|
|
{
|
|
|
|
char * p;
|
|
|
|
|
|
|
|
if (arg[0] == '@') {
|
|
|
|
expand_diversion(arg + 1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (p = arg; *p != 0; p++) {
|
|
|
|
if (*p == '*' || *p == '?') {
|
|
|
|
expand_pattern(arg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
store_argument(arg);
|
|
|
|
}
|
|
|
|
|
1997-09-02 05:55:01 -07:00
|
|
|
static void expand_pattern(char * pat)
|
1996-09-06 09:51:56 -07:00
|
|
|
{
|
|
|
|
int handle;
|
|
|
|
struct _finddata_t ffblk;
|
2001-12-03 01:52:10 -08:00
|
|
|
int preflen;
|
1996-09-06 09:51:56 -07:00
|
|
|
|
|
|
|
handle = _findfirst(pat, &ffblk);
|
|
|
|
if (handle == -1) {
|
1997-05-19 08:42:21 -07:00
|
|
|
store_argument(pat); /* a la Bourne shell */
|
|
|
|
return;
|
1996-09-06 09:51:56 -07:00
|
|
|
}
|
2001-12-03 01:52:10 -08:00
|
|
|
for (preflen = strlen(pat); preflen > 0; preflen--) {
|
|
|
|
char c = pat[preflen - 1];
|
|
|
|
if (c == '\\' || c == '/' || c == ':') break;
|
|
|
|
}
|
1996-09-06 09:51:56 -07:00
|
|
|
do {
|
2001-12-03 01:52:10 -08:00
|
|
|
char * name = malloc(preflen + strlen(ffblk.name) + 1);
|
|
|
|
if (name == NULL) out_of_memory();
|
|
|
|
memcpy(name, pat, preflen);
|
|
|
|
strcpy(name + preflen, ffblk.name);
|
|
|
|
store_argument(name);
|
1996-09-06 09:51:56 -07:00
|
|
|
} while (_findnext(handle, &ffblk) != -1);
|
|
|
|
_findclose(handle);
|
|
|
|
}
|
|
|
|
|
1997-09-02 05:55:01 -07:00
|
|
|
static void expand_diversion(char * filename)
|
1996-09-06 09:51:56 -07:00
|
|
|
{
|
|
|
|
struct _stat stat;
|
|
|
|
int fd;
|
2002-11-17 08:34:08 -08:00
|
|
|
char * buf, * endbuf, * p, * q, * s;
|
|
|
|
int inquote;
|
1996-09-06 09:51:56 -07:00
|
|
|
|
|
|
|
if (_stat(filename, &stat) == -1 ||
|
|
|
|
(fd = _open(filename, O_RDONLY | O_BINARY, 0)) == -1) {
|
|
|
|
fprintf(stderr, "Cannot open file %s\n", filename);
|
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
buf = (char *) malloc(stat.st_size + 1);
|
|
|
|
if (buf == NULL) out_of_memory();
|
|
|
|
_read(fd, buf, stat.st_size);
|
|
|
|
endbuf = buf + stat.st_size;
|
|
|
|
_close(fd);
|
|
|
|
for (p = buf; p < endbuf; /*nothing*/) {
|
|
|
|
/* Skip leading blanks */
|
|
|
|
while (p < endbuf && isspace(*p)) p++;
|
1997-05-19 08:42:21 -07:00
|
|
|
if (p >= endbuf) break;
|
1996-09-06 09:51:56 -07:00
|
|
|
s = p;
|
2002-11-17 08:34:08 -08:00
|
|
|
/* Skip to end of argument, taking quotes into account */
|
|
|
|
q = s;
|
|
|
|
inquote = 0;
|
|
|
|
while (p < endbuf) {
|
|
|
|
if (! inquote) {
|
|
|
|
if (isspace(*p)) break;
|
|
|
|
if (*p == '"') { inquote = 1; p++; continue; }
|
|
|
|
*q++ = *p++;
|
|
|
|
} else {
|
|
|
|
switch (*p) {
|
|
|
|
case '"':
|
|
|
|
inquote = 0; p++; continue;
|
|
|
|
case '\\':
|
|
|
|
if (p + 4 <= endbuf && strncmp(p, "\\\\\\\"", 4) == 0) {
|
|
|
|
p += 4; *q++ = '\\'; *q++ = '"'; continue;
|
|
|
|
}
|
|
|
|
if (p + 3 <= endbuf && strncmp(p, "\\\\\"", 3) == 0) {
|
|
|
|
p += 3; *q++ = '\\'; inquote = 0; continue;
|
|
|
|
}
|
|
|
|
if (p + 2 <= endbuf && p[1] == '"') {
|
|
|
|
p += 2; *q++ = '"'; continue;
|
|
|
|
}
|
|
|
|
/* fallthrough */
|
|
|
|
default:
|
|
|
|
*q++ = *p++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1996-09-06 09:51:56 -07:00
|
|
|
/* Delimit argument and expand it */
|
2002-11-17 08:34:08 -08:00
|
|
|
*q++ = 0;
|
1996-09-06 09:51:56 -07:00
|
|
|
expand_argument(s);
|
2002-11-17 08:34:08 -08:00
|
|
|
p++;
|
1996-09-06 09:51:56 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-01-01 08:42:43 -08:00
|
|
|
CAMLexport void caml_expand_command_line(int * argcp, char *** argvp)
|
1996-09-06 09:51:56 -07:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
argc = 0;
|
|
|
|
argvsize = 16;
|
|
|
|
argv = (char **) malloc(argvsize * sizeof(char *));
|
|
|
|
if (argv == NULL) out_of_memory();
|
|
|
|
for (i = 0; i < *argcp; i++) expand_argument((*argvp)[i]);
|
|
|
|
argv[argc] = NULL;
|
|
|
|
*argcp = argc;
|
|
|
|
*argvp = argv;
|
|
|
|
}
|
2000-04-04 06:19:12 -07:00
|
|
|
|
2003-03-03 09:16:15 -08:00
|
|
|
/* Add to [contents] the (short) names of the files contained in
|
|
|
|
the directory named [dirname]. No entries are added for [.] and [..].
|
|
|
|
Return 0 on success, -1 on error; set errno in the case of error. */
|
|
|
|
|
|
|
|
int caml_read_directory(char * dirname, struct ext_table * contents)
|
|
|
|
{
|
2003-03-24 07:25:13 -08:00
|
|
|
char * template;
|
2006-10-01 08:40:28 -07:00
|
|
|
#if _MSC_VER <= 1200
|
|
|
|
int h;
|
|
|
|
#else
|
2005-09-22 07:21:50 -07:00
|
|
|
intptr_t h;
|
2006-10-01 08:40:28 -07:00
|
|
|
#endif
|
2003-03-03 09:16:15 -08:00
|
|
|
struct _finddata_t fileinfo;
|
|
|
|
char * p;
|
|
|
|
|
2003-12-31 06:20:40 -08:00
|
|
|
template = caml_stat_alloc(strlen(dirname) + 5);
|
2003-03-24 07:25:13 -08:00
|
|
|
strcpy(template, dirname);
|
|
|
|
strcat(template, "\\*.*");
|
|
|
|
h = _findfirst(template, &fileinfo);
|
2003-12-31 06:20:40 -08:00
|
|
|
caml_stat_free(template);
|
2003-03-03 09:16:15 -08:00
|
|
|
if (h == -1) return errno == ENOENT ? 0 : -1;
|
|
|
|
do {
|
|
|
|
if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0) {
|
2003-12-31 06:20:40 -08:00
|
|
|
p = caml_stat_alloc(strlen(fileinfo.name) + 1);
|
2003-03-03 09:16:15 -08:00
|
|
|
strcpy(p, fileinfo.name);
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_ext_table_add(contents, p);
|
2003-03-03 09:16:15 -08:00
|
|
|
}
|
|
|
|
} while (_findnext(h, &fileinfo) == 0);
|
|
|
|
_findclose(h);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-04-21 05:41:51 -07:00
|
|
|
#ifndef NATIVE_CODE
|
|
|
|
|
2002-07-23 20:22:38 -07:00
|
|
|
/* Set up a new thread for control-C emulation and termination */
|
2000-04-04 06:19:12 -07:00
|
|
|
|
2001-04-10 04:14:33 -07:00
|
|
|
void caml_signal_thread(void * lpParam)
|
2000-04-04 06:19:12 -07:00
|
|
|
{
|
2001-04-10 04:14:33 -07:00
|
|
|
char *endptr;
|
2000-04-04 06:19:12 -07:00
|
|
|
HANDLE h;
|
|
|
|
/* Get an hexa-code raw handle through the environment */
|
2001-04-10 04:14:33 -07:00
|
|
|
h = (HANDLE) strtol(getenv("CAMLSIGPIPE"), &endptr, 16);
|
2000-04-04 06:19:12 -07:00
|
|
|
while (1) {
|
|
|
|
DWORD numread;
|
|
|
|
BOOL ret;
|
|
|
|
char iobuf[2];
|
|
|
|
/* This shall always return a single character */
|
|
|
|
ret = ReadFile(h, iobuf, 1, &numread, NULL);
|
2003-12-15 10:37:24 -08:00
|
|
|
if (!ret || numread != 1) caml_sys_exit(Val_int(2));
|
2000-04-04 06:19:12 -07:00
|
|
|
switch (iobuf[0]) {
|
|
|
|
case 'C':
|
2005-10-12 05:33:47 -07:00
|
|
|
caml_record_signal(SIGINT);
|
2000-04-04 06:19:12 -07:00
|
|
|
break;
|
|
|
|
case 'T':
|
2002-07-23 20:22:38 -07:00
|
|
|
raise(SIGTERM);
|
|
|
|
return;
|
2000-04-04 06:19:12 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-04-21 05:41:51 -07:00
|
|
|
|
2004-01-08 14:28:48 -08:00
|
|
|
#endif /* NATIVE_CODE */
|