#include "lisp.h"
#include "buffer.h"
+
+#include "syssignal.h"
+#include "systime.h"
#include "syswindows.h"
typedef BOOL (WINAPI *pfSwitchToThread_t) (VOID);
/* Encode filename and current directory. */
Lisp_Object current_dir = Ffile_name_directory (document);
char* path = NULL;
+#ifdef CYGWIN
+ char* fname1, *fname2;
+ int pos, sz;
+#endif
char* doc = NULL;
- Extbyte* f=0;
int ret;
struct gcpro gcpro1, gcpro2;
/* Use mule and cygwin-safe APIs top get at file data. */
if (STRINGP (current_dir))
{
- TO_EXTERNAL_FORMAT (LISP_STRING, current_dir,
- C_STRING_ALLOCA, f,
- Qfile_name);
-#ifdef CYGWIN
- CYGWIN_WIN32_PATH (f, path);
-#else
- path = f;
-#endif
+ LOCAL_TO_WIN32_FILE_FORMAT (current_dir, path);
}
if (STRINGP (document))
{
- TO_EXTERNAL_FORMAT (LISP_STRING, document,
- C_STRING_ALLOCA, f,
- Qfile_name);
+ doc = XSTRING_DATA (document);
#ifdef CYGWIN
- CYGWIN_WIN32_PATH (f, doc);
-#else
- doc = f;
+ if ((fname1 = strchr (doc, ':')) != NULL
+ && *++fname1 == '/' && *++fname1 == '/')
+ {
+ // URL-style if we get here, but we must only convert file
+ // arguments, since win32 paths are illegal in http etc.
+ if (strncmp (doc, "file://", 7) == 0)
+ {
+ fname1++;
+ pos = fname1 - doc;
+ if (!(isalpha (fname1[0]) && (IS_DEVICE_SEP (fname1[1]))))
+ {
+ sz = cygwin_posix_to_win32_path_list_buf_size (fname1);
+ fname2 = alloca (sz + pos);
+ strncpy (fname2, doc, pos);
+ doc = fname2;
+ fname2 += pos;
+ cygwin_posix_to_win32_path_list (fname1, fname2);
+ }
+ }
+ }
+ else {
+ // Not URL-style, must be a straight filename.
+ LOCAL_TO_WIN32_FILE_FORMAT (document, doc);
+ }
#endif
}
return Qnil;
}
+#ifdef CYGWIN
+DEFUN ("mswindows-cygwin-to-win32-path", Fmswindows_cygwin_to_win32_path, 1, 1, 0, /*
+Get the cygwin environment to convert the Unix PATH to win32 format.
+No expansion is performed, all conversion is done by the cygwin runtime.
+*/
+ (path))
+{
+ Extbyte* f;
+ Bufbyte* p;
+ CHECK_STRING (path);
+
+ /* There appears to be a bug in the cygwin conversion routines in
+ that they are not idempotent. */
+ p = XSTRING_DATA (path);
+ if (isalpha (p[0]) && (IS_DEVICE_SEP (p[1])))
+ return path;
+
+ /* Use mule and cygwin-safe APIs top get at file data. */
+ LOCAL_TO_WIN32_FILE_FORMAT (path, f);
+ return build_ext_string (f, Qnative);
+}
+#endif
+
+\f
+/*--------------------------------------------------------------------*/
+/* Async timers */
+/*--------------------------------------------------------------------*/
+
+/* setitimer() does not exist on native MS Windows, and appears broken
+ on Cygwin (random lockups when BROKEN_SIGIO is defined), so we
+ emulate in both cases by using multimedia timers. */
+
+/* We emulate two timers, one for SIGALRM, another for SIGPROF.
+
+ itimerproc() function has an implementation limitation: it does
+ not allow to set *both* interval and period. If an attempt is
+ made to set both, and then they are unequal, the function
+ asserts.
+
+ Minimum timer resolution on Win32 systems varies, and is greater
+ than or equal than 1 ms. The resolution is always wrapped not to
+ attempt to get below the system defined limit.
+ */
+
+/* Timer precision, denominator of one fraction: for 100 ms
+ interval, request 10 ms precision
+ */
+const int setitimer_helper_timer_prec = 10;
+
+/* Last itimervals, as set by calls to setitimer */
+static struct itimerval it_alarm;
+static struct itimerval it_prof;
+
+/* Timer IDs as returned by MM */
+MMRESULT tid_alarm = 0;
+MMRESULT tid_prof = 0;
+
+static void CALLBACK
+setitimer_helper_proc (UINT uID, UINT uMsg, DWORD dwUser,
+ DWORD dw1, DWORD dw2)
+{
+ /* Just raise the signal indicated by the dwUser parameter */
+#ifdef CYGWIN
+ kill (getpid (), dwUser);
+#else
+ mswindows_raise (dwUser);
+#endif
+}
+
+/* Divide time in ms specified by IT by DENOM. Return 1 ms
+ if division results in zero */
+static UINT
+setitimer_helper_period (const struct itimerval* it, UINT denom)
+{
+ static TIMECAPS time_caps;
+
+ UINT res;
+ const struct timeval* tv =
+ (it->it_value.tv_sec == 0 && it->it_value.tv_usec == 0)
+ ? &it->it_interval : &it->it_value;
+
+ /* Zero means stop timer */
+ if (tv->tv_sec == 0 && tv->tv_usec == 0)
+ return 0;
+
+ /* Convert to ms and divide by denom */
+ res = (tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000) / denom;
+
+ /* Converge to minimum timer resolution */
+ if (time_caps.wPeriodMin == 0)
+ timeGetDevCaps (&time_caps, sizeof(time_caps));
+
+ if (res < time_caps.wPeriodMin)
+ res = time_caps.wPeriodMin;
+
+ return res;
+}
+
+static int
+setitimer_helper (const struct itimerval* itnew,
+ struct itimerval* itold, struct itimerval* itcurrent,
+ MMRESULT* tid, DWORD sigkind)
+{
+ UINT delay, resolution, event_type;
+
+ /* First stop the old timer */
+ if (*tid)
+ {
+ timeKillEvent (*tid);
+ timeEndPeriod (setitimer_helper_period (itcurrent,
+ setitimer_helper_timer_prec));
+ *tid = 0;
+ }
+
+ /* Return old itimerval if requested */
+ if (itold)
+ *itold = *itcurrent;
+
+ *itcurrent = *itnew;
+
+ /* Determine if to start new timer */
+ delay = setitimer_helper_period (itnew, 1);
+ if (delay)
+ {
+ resolution = setitimer_helper_period (itnew,
+ setitimer_helper_timer_prec);
+ event_type = (itnew->it_value.tv_sec == 0 &&
+ itnew->it_value.tv_usec == 0)
+ ? TIME_ONESHOT : TIME_PERIODIC;
+ timeBeginPeriod (resolution);
+ *tid = timeSetEvent (delay, resolution, setitimer_helper_proc, sigkind,
+ event_type);
+ }
+
+ return !delay || *tid;
+}
+
+int
+mswindows_setitimer (int kind, const struct itimerval *itnew,
+ struct itimerval *itold)
+{
+ /* In this version, both interval and value are allowed
+ only if they are equal. */
+ assert ((itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
+ || (itnew->it_interval.tv_sec == 0 &&
+ itnew->it_interval.tv_usec == 0)
+ || (itnew->it_value.tv_sec == itnew->it_interval.tv_sec &&
+ itnew->it_value.tv_usec == itnew->it_interval.tv_usec));
+
+ if (kind == ITIMER_REAL)
+ return setitimer_helper (itnew, itold, &it_alarm, &tid_alarm, SIGALRM);
+ else if (kind == ITIMER_PROF)
+ return setitimer_helper (itnew, itold, &it_prof, &tid_prof, SIGPROF);
+ else
+ return errno = EINVAL;
+}
+
+\f
void
syms_of_win32 (void)
{
DEFSUBR (Fmswindows_shell_execute);
+#ifdef CYGWIN
+ DEFSUBR (Fmswindows_cygwin_to_win32_path);
+#endif
}
void