/* Interfaces to system-dependent kernel and library entries.
- Copyright (C) 1985-1988, 1993-1995, 1999-2013 Free Software
+ Copyright (C) 1985-1988, 1993-1995, 1999-2014 Free Software
Foundation, Inc.
This file is part of GNU Emacs.
#include <config.h>
-#define SYSTIME_INLINE EXTERN_INLINE
+/* If HYBRID_GET_CURRENT_DIR_NAME is defined in conf_post.h, then we
+ need the following before including unistd.h, in order to pick up
+ the right prototype for gget_current_dir_name. */
+#ifdef HYBRID_GET_CURRENT_DIR_NAME
+#undef get_current_dir_name
+#define get_current_dir_name gget_current_dir_name
+#endif
#include <execinfo.h>
#include "sysstdio.h"
# include <sys/user.h>
# undef frame
-# include <sys/resource.h>
# include <math.h>
#endif
#include "msdos.h"
#endif
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
#include <sys/param.h>
#include <sys/file.h>
#include <fcntl.h>
#include "syssignal.h"
#include "systime.h"
-static void emacs_get_tty (int, struct emacs_tty *);
-static int emacs_set_tty (int, struct emacs_tty *, bool);
-
/* ULLONG_MAX is missing on Red Hat Linux 7.3; see Bug#11781. */
#ifndef ULLONG_MAX
#define ULLONG_MAX TYPE_MAXIMUM (unsigned long long int)
1800, 2400, 4800, 9600, 19200, 38400
};
-
-#if !defined (HAVE_GET_CURRENT_DIR_NAME) || defined (BROKEN_GET_CURRENT_DIR_NAME)
-
+#if !defined HAVE_GET_CURRENT_DIR_NAME || defined BROKEN_GET_CURRENT_DIR_NAME \
+ || (defined HYBRID_GET_CURRENT_DIR_NAME)
/* Return the current working directory. Returns NULL on errors.
Any other returned value must be freed with free. This is used
only when get_current_dir_name is not defined on the system. */
-char*
+char *
get_current_dir_name (void)
{
char *buf;
void
stuff_char (char c)
{
- if (! FRAME_TERMCAP_P (SELECTED_FRAME ()))
+ if (! (FRAMEP (selected_frame)
+ && FRAME_LIVE_P (XFRAME (selected_frame))
+ && FRAME_TERMCAP_P (XFRAME (selected_frame))))
return;
/* Should perhaps error if in batch mode */
#endif /* not DOS_NT */
}
- baud_rate = (emacs_ospeed < sizeof baud_convert / sizeof baud_convert[0]
+ baud_rate = (emacs_ospeed < ARRAYELTS (baud_convert)
? baud_convert[emacs_ospeed] : 9600);
if (baud_rate == 0)
baud_rate = 1200;
/* If successful and status is requested, tell wait_reading_process_output
that it needs to wake up and look around. */
if (pid && status && input_available_clear_time)
- *input_available_clear_time = make_emacs_time (0, 0);
+ *input_available_clear_time = make_timespec (0, 0);
return pid;
}
{
#ifdef DOS_NT /* Demacs 1.1.2 91/10/20 Manabu Higashida */
int st;
+#ifdef MSDOS
char oldwd[MAXPATHLEN+1]; /* Fixed length is safe on MSDOS. */
+#else
+ char oldwd[MAX_UTF8_PATH];
+#endif
#endif
pid_t pid;
int status;
struct save_signal saved_handlers[5];
- Lisp_Object dir;
- unsigned char *volatile str_volatile = 0;
- unsigned char *str;
- int len;
+ char *str = SSDATA (encode_current_directory ());
+
+#ifdef DOS_NT
+ pid = 0;
+#else
+ {
+ char *volatile str_volatile = str;
+ pid = vfork ();
+ str = str_volatile;
+ }
+#endif
+
+ if (pid < 0)
+ error ("Can't spawn subshell");
saved_handlers[0].code = SIGINT;
saved_handlers[1].code = SIGQUIT;
saved_handlers[3].code = 0;
#endif
- /* Mentioning current_buffer->buffer would mean including buffer.h,
- which somehow wedges the hp compiler. So instead... */
-
- dir = intern ("default-directory");
- if (NILP (Fboundp (dir)))
- goto xyzzy;
- dir = Fsymbol_value (dir);
- if (!STRINGP (dir))
- goto xyzzy;
-
- dir = expand_and_dir_to_file (Funhandled_file_name_directory (dir), Qnil);
- str_volatile = str = alloca (SCHARS (dir) + 2);
- len = SCHARS (dir);
- memcpy (str, SDATA (dir), len);
- if (str[len - 1] != '/') str[len++] = '/';
- str[len] = 0;
- xyzzy:
-
#ifdef DOS_NT
- pid = 0;
save_signal_handlers (saved_handlers);
-#else
- pid = vfork ();
- if (pid == -1)
- error ("Can't spawn subshell");
#endif
if (pid == 0)
sh = "sh";
/* Use our buffer's default directory for the subshell. */
- str = str_volatile;
- if (str && chdir ((char *) str) != 0)
+ if (chdir (str) != 0)
{
#ifndef DOS_NT
- emacs_perror ((char *) str);
+ emacs_perror (str);
_exit (EXIT_CANCELED);
#endif
}
if (epwd)
{
strcpy (old_pwd, epwd);
- if (str[len - 1] == '/')
- str[len - 1] = '\0';
setenv ("PWD", str, 1);
}
st = system (sh);
}
\f
#ifdef USABLE_SIGIO
-static int old_fcntl_flags[MAXDESC];
+static int old_fcntl_flags[FD_SETSIZE];
#endif
void
#endif
}
+#ifndef DOS_NT
static void
reset_sigio (int fd)
{
fcntl (fd, F_SETFL, old_fcntl_flags[fd]);
#endif
}
+#endif
void
request_sigio (void)
signal (SIGIO, SIG_IGN);
#endif
}
+\f
+#ifndef MSDOS
+/* Block SIGCHLD. */
+
+void
+block_child_signal (sigset_t *oldset)
+{
+ sigset_t blocked;
+ sigemptyset (&blocked);
+ sigaddset (&blocked, SIGCHLD);
+ sigaddset (&blocked, SIGINT);
+ pthread_sigmask (SIG_BLOCK, &blocked, oldset);
+}
+/* Unblock SIGCHLD. */
+
+void
+unblock_child_signal (sigset_t const *oldset)
+{
+ pthread_sigmask (SIG_SETMASK, oldset, 0);
+}
+
+#endif /* !MSDOS */
\f
/* Saving and restoring the process group of Emacs's terminal. */
/* Block and unblock SIGTTOU. */
void
-block_tty_out_signal (void)
+block_tty_out_signal (sigset_t *oldset)
{
#ifdef SIGTTOU
sigset_t blocked;
sigemptyset (&blocked);
sigaddset (&blocked, SIGTTOU);
- pthread_sigmask (SIG_BLOCK, &blocked, 0);
+ pthread_sigmask (SIG_BLOCK, &blocked, oldset);
#endif
}
void
-unblock_tty_out_signal (void)
+unblock_tty_out_signal (sigset_t const *oldset)
{
#ifdef SIGTTOU
- pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+ pthread_sigmask (SIG_SETMASK, oldset, 0);
#endif
}
tcsetpgrp_without_stopping (int fd, pid_t pgid)
{
#ifdef SIGTTOU
+ sigset_t oldset;
block_input ();
- block_tty_out_signal ();
+ block_tty_out_signal (&oldset);
tcsetpgrp (fd, pgid);
- unblock_tty_out_signal ();
+ unblock_tty_out_signal (&oldset);
unblock_input ();
#endif
}
/* Getting and setting emacs_tty structures. */
/* Set *TC to the parameters associated with the terminal FD,
- or clear it if the parameters are not available. */
-static void
+ or clear it if the parameters are not available.
+ Return 0 on success, -1 on failure. */
+int
emacs_get_tty (int fd, struct emacs_tty *settings)
{
/* Retrieve the primary parameters - baud rate, character size, etcetera. */
-#ifndef DOS_NT
- /* We have those nifty POSIX tcmumbleattr functions. */
memset (&settings->main, 0, sizeof (settings->main));
- tcgetattr (fd, &settings->main);
+#ifdef DOS_NT
+#ifdef WINDOWSNT
+ HANDLE h = (HANDLE)_get_osfhandle (fd);
+ DWORD console_mode;
+
+ if (h && h != INVALID_HANDLE_VALUE && GetConsoleMode (h, &console_mode))
+ {
+ settings->main = console_mode;
+ return 0;
+ }
+#endif /* WINDOWSNT */
+ return -1;
+#else /* !DOS_NT */
+ /* We have those nifty POSIX tcmumbleattr functions. */
+ return tcgetattr (fd, &settings->main);
#endif
}
*SETTINGS. If FLUSHP, discard input.
Return 0 if all went well, and -1 (setting errno) if anything failed. */
-static int
+int
emacs_set_tty (int fd, struct emacs_tty *settings, bool flushp)
{
/* Set the primary parameters - baud rate, character size, etcetera. */
-#ifndef DOS_NT
+#ifdef DOS_NT
+#ifdef WINDOWSNT
+ HANDLE h = (HANDLE)_get_osfhandle (fd);
+
+ if (h && h != INVALID_HANDLE_VALUE)
+ {
+ DWORD new_mode;
+
+ /* Assume the handle is open for input. */
+ if (flushp)
+ FlushConsoleInputBuffer (h);
+ new_mode = settings->main;
+ SetConsoleMode (h, new_mode);
+ }
+#endif /* WINDOWSNT */
+#else /* !DOS_NT */
int i;
/* We have those nifty POSIX tcmumbleattr functions.
William J. Smith <wjs@wiis.wang.com> writes:
\f
#ifdef F_SETOWN
-static int old_fcntl_owner[MAXDESC];
+static int old_fcntl_owner[FD_SETSIZE];
#endif /* F_SETOWN */
/* This may also be defined in stdio,
return 0;
#endif /* DOS_NT */
}
+
+/* Discard echoing. */
+
+void
+suppress_echo_on_tty (int fd)
+{
+ struct emacs_tty etty;
+
+ emacs_get_tty (fd, &etty);
+#ifdef DOS_NT
+ /* Set raw input mode. */
+ etty.main = 0;
+#else
+ etty.main.c_lflag &= ~ICANON; /* Disable buffering */
+ etty.main.c_lflag &= ~ECHO; /* Disable echoing */
+#endif /* ! WINDOWSNT */
+ emacs_set_tty (fd, &etty, 0);
+}
\f
/* Get terminal size from system.
Store number of lines into *HEIGHTP and width into *WIDTHP.
}
/* Set the logical window size associated with descriptor FD
- to HEIGHT and WIDTH. This is used mainly with ptys. */
+ to HEIGHT and WIDTH. This is used mainly with ptys.
+ Return a negative value on failure. */
int
set_window_size (int fd, int height, int width)
size.ws_row = height;
size.ws_col = width;
- if (ioctl (fd, TIOCSWINSZ, &size) == -1)
- return 0; /* error */
- else
- return 1;
+ return ioctl (fd, TIOCSWINSZ, &size);
#else
#ifdef TIOCSSIZE
size.ts_lines = height;
size.ts_cols = width;
- if (ioctl (fd, TIOCGSIZE, &size) == -1)
- return 0;
- else
- return 1;
+ return ioctl (fd, TIOCGSIZE, &size);
#else
return -1;
#endif /* not SunOS-style */
int i;
tty_turn_off_insert (tty_out);
- for (i = curX (tty_out); i < FrameCols (tty_out) - 1; i++)
+ for (i = cursorX (tty_out); i < FrameCols (tty_out) - 1; i++)
{
fputc (' ', tty_out->output);
}
/* When handling a signal, block nonfatal system signals that are caught
by Emacs. This makes race conditions less likely. */
sigaddset (&action->sa_mask, SIGALRM);
+#ifdef SIGCHLD
sigaddset (&action->sa_mask, SIGCHLD);
+#endif
#ifdef SIGDANGER
sigaddset (&action->sa_mask, SIGDANGER);
#endif
#endif
}
- if (! IEEE_FLOATING_POINT)
- sigaddset (&action->sa_mask, SIGFPE);
-
action->sa_handler = handler;
action->sa_flags = emacs_sigaction_flags ();
}
xsignal0 (Qarith_error);
}
+#ifdef HAVE_STACK_OVERFLOW_HANDLING
+
+/* -1 if stack grows down as expected on most OS/ABI variants, 1 otherwise. */
+
+static int stack_direction;
+
+/* Alternate stack used by SIGSEGV handler below. */
+
+static unsigned char sigsegv_stack[SIGSTKSZ];
+
+/* Attempt to recover from SIGSEGV caused by C stack overflow. */
+
+static void
+handle_sigsegv (int sig, siginfo_t *siginfo, void *arg)
+{
+ /* Hard GC error may lead to stack overflow caused by
+ too nested calls to mark_object. No way to survive. */
+ if (!gc_in_progress)
+ {
+ struct rlimit rlim;
+
+ if (!getrlimit (RLIMIT_STACK, &rlim))
+ {
+ enum { STACK_DANGER_ZONE = 16 * 1024 };
+ char *beg, *end, *addr;
+
+ beg = stack_bottom;
+ end = stack_bottom + stack_direction * rlim.rlim_cur;
+ if (beg > end)
+ addr = beg, beg = end, end = addr;
+ addr = (char *) siginfo->si_addr;
+ /* If we're somewhere on stack and too close to
+ one of its boundaries, most likely this is it. */
+ if (beg < addr && addr < end
+ && (addr - beg < STACK_DANGER_ZONE
+ || end - addr < STACK_DANGER_ZONE))
+ siglongjmp (return_to_command_loop, 1);
+ }
+ }
+
+ /* Otherwise we can't do anything with this. */
+ deliver_fatal_thread_signal (sig);
+}
+
+/* Return true if we have successfully set up SIGSEGV handler on alternate
+ stack. Otherwise we just treat SIGSEGV among the rest of fatal signals. */
+
+static bool
+init_sigsegv (void)
+{
+ struct sigaction sa;
+ stack_t ss;
+
+ stack_direction = ((char *) &ss < stack_bottom) ? -1 : 1;
+
+ ss.ss_sp = sigsegv_stack;
+ ss.ss_size = sizeof (sigsegv_stack);
+ ss.ss_flags = 0;
+ if (sigaltstack (&ss, NULL) < 0)
+ return 0;
+
+ sigfillset (&sa.sa_mask);
+ sa.sa_sigaction = handle_sigsegv;
+ sa.sa_flags = SA_SIGINFO | SA_ONSTACK | emacs_sigaction_flags ();
+ return sigaction (SIGSEGV, &sa, NULL) < 0 ? 0 : 1;
+}
+
+#else /* not HAVE_STACK_OVERFLOW_HANDLING */
+
+static bool
+init_sigsegv (void)
+{
+ return 0;
+}
+
+#endif /* HAVE_STACK_OVERFLOW_HANDLING */
+
static void
deliver_arith_signal (int sig)
{
# ifdef SIGBUS
sys_siglist[SIGBUS] = "Bus error";
# endif
+# ifdef SIGCHLD
sys_siglist[SIGCHLD] = "Child status changed";
+# endif
# ifdef SIGCONT
sys_siglist[SIGCONT] = "Continued";
# endif
#ifdef SIGBUS
sigaction (SIGBUS, &thread_fatal_action, 0);
#endif
- sigaction (SIGSEGV, &thread_fatal_action, 0);
+ if (!init_sigsegv ())
+ sigaction (SIGSEGV, &thread_fatal_action, 0);
#ifdef SIGSYS
sigaction (SIGSYS, &thread_fatal_action, 0);
#endif
void
init_random (void)
{
- EMACS_TIME t = current_emacs_time ();
- uintmax_t v = getpid () ^ EMACS_SECS (t) ^ EMACS_NSECS (t);
+ struct timespec t = current_timespec ();
+ uintmax_t v = getpid () ^ t.tv_sec ^ t.tv_nsec;
seed_random (&v, sizeof v);
}
#endif
/* Open FILE for Emacs use, using open flags OFLAG and mode MODE.
+ Use binary I/O on systems that care about text vs binary I/O.
Arrange for subprograms to not inherit the file descriptor.
Prefer a method that is multithread-safe, if available.
Do not fail merely because the open was interrupted by a signal.
emacs_open (const char *file, int oflags, int mode)
{
int fd;
+ if (! (oflags & O_TEXT))
+ oflags |= O_BINARY;
oflags |= O_CLOEXEC;
while ((fd = open (file, oflags, mode)) < 0 && errno == EINTR)
QUIT;
int
emacs_pipe (int fd[2])
{
- int result = pipe2 (fd, O_CLOEXEC);
+#ifdef MSDOS
+ return pipe (fd);
+#else /* !MSDOS */
+ int result = pipe2 (fd, O_BINARY | O_CLOEXEC);
if (! O_CLOEXEC && result == 0)
{
fcntl (fd[0], F_SETFD, FD_CLOEXEC);
fcntl (fd[1], F_SETFD, FD_CLOEXEC);
}
return result;
+#endif /* !MSDOS */
}
/* Approximate posix_close and POSIX_CLOSE_RESTART well enough for Emacs.
Return the number of bytes read, which might be less than NBYTE.
On error, set errno and return -1. */
ptrdiff_t
-emacs_read (int fildes, char *buf, ptrdiff_t nbyte)
+emacs_read (int fildes, void *buf, ptrdiff_t nbyte)
{
- register ssize_t rtnval;
+ ssize_t rtnval;
/* There is no need to check against MAX_RW_COUNT, since no caller ever
passes a size that large to emacs_read. */
interrupted or if a partial write occurs. Return the number of
bytes written, setting errno if this is less than NBYTE. */
ptrdiff_t
-emacs_write (int fildes, char const *buf, ptrdiff_t nbyte)
+emacs_write (int fildes, void const *buf, ptrdiff_t nbyte)
{
return emacs_full_write (fildes, buf, nbyte, 0);
}
/* Like emacs_write, but also process pending signals if interrupted. */
ptrdiff_t
-emacs_write_sig (int fildes, char const *buf, ptrdiff_t nbyte)
+emacs_write_sig (int fildes, void const *buf, ptrdiff_t nbyte)
{
return emacs_full_write (fildes, buf, nbyte, 1);
}
Use the least timeval not less than T.
Return an extremal value if the result would overflow. */
struct timeval
-make_timeval (EMACS_TIME t)
+make_timeval (struct timespec t)
{
struct timeval tv;
tv.tv_sec = t.tv_sec;
If FD is nonnegative, then FILE can be NULL. */
int
set_file_times (int fd, const char *filename,
- EMACS_TIME atime, EMACS_TIME mtime)
+ struct timespec atime, struct timespec mtime)
{
struct timespec timespec[2];
timespec[0] = atime;
Lisp_Object childp2 = Qnil;
Lisp_Object tem = Qnil;
struct termios attr;
- int err = -1;
+ int err;
char summary[4] = "???"; /* This usually becomes "8N1". */
childp2 = Fcopy_sequence (p->childp);
#endif /* !defined (WINDOWSNT) */
#if defined GNU_LINUX && defined HAVE_LONG_LONG_INT
-static EMACS_TIME
+static struct timespec
time_from_jiffies (unsigned long long tval, long hz)
{
unsigned long long s = tval / hz;
if (TYPE_MAXIMUM (time_t) < s)
time_overflow ();
- if (LONG_MAX - 1 <= ULLONG_MAX / EMACS_TIME_RESOLUTION
- || frac <= ULLONG_MAX / EMACS_TIME_RESOLUTION)
- ns = frac * EMACS_TIME_RESOLUTION / hz;
+ if (LONG_MAX - 1 <= ULLONG_MAX / TIMESPEC_RESOLUTION
+ || frac <= ULLONG_MAX / TIMESPEC_RESOLUTION)
+ ns = frac * TIMESPEC_RESOLUTION / hz;
else
{
/* This is reachable only in the unlikely case that HZ * HZ
exceeds ULLONG_MAX. It calculates an approximation that is
guaranteed to be in range. */
- long hz_per_ns = (hz / EMACS_TIME_RESOLUTION
- + (hz % EMACS_TIME_RESOLUTION != 0));
+ long hz_per_ns = (hz / TIMESPEC_RESOLUTION
+ + (hz % TIMESPEC_RESOLUTION != 0));
ns = frac / hz_per_ns;
}
- return make_emacs_time (s, ns);
+ return make_timespec (s, ns);
}
static Lisp_Object
ltime_from_jiffies (unsigned long long tval, long hz)
{
- EMACS_TIME t = time_from_jiffies (tval, hz);
+ struct timespec t = time_from_jiffies (tval, hz);
return make_lisp_time (t);
}
-static EMACS_TIME
+static struct timespec
get_up_time (void)
{
FILE *fup;
- EMACS_TIME up = make_emacs_time (0, 0);
+ struct timespec up = make_timespec (0, 0);
block_input ();
fup = emacs_fopen ("/proc/uptime", "r");
if (TYPE_MAXIMUM (time_t) < upsec)
{
upsec = TYPE_MAXIMUM (time_t);
- upfrac = EMACS_TIME_RESOLUTION - 1;
+ upfrac = TIMESPEC_RESOLUTION - 1;
}
else
{
int upfraclen = upfrac_end - upfrac_start;
- for (; upfraclen < LOG10_EMACS_TIME_RESOLUTION; upfraclen++)
+ for (; upfraclen < LOG10_TIMESPEC_RESOLUTION; upfraclen++)
upfrac *= 10;
- for (; LOG10_EMACS_TIME_RESOLUTION < upfraclen; upfraclen--)
+ for (; LOG10_TIMESPEC_RESOLUTION < upfraclen; upfraclen--)
upfrac /= 10;
- upfrac = min (upfrac, EMACS_TIME_RESOLUTION - 1);
+ upfrac = min (upfrac, TIMESPEC_RESOLUTION - 1);
}
- up = make_emacs_time (upsec, upfrac);
+ up = make_timespec (upsec, upfrac);
}
fclose (fup);
}
return build_string (name);
}
-static unsigned long
+static uintmax_t
procfs_get_total_memory (void)
{
FILE *fmem;
- unsigned long retval = 2 * 1024 * 1024; /* default: 2GB */
+ uintmax_t retval = 2 * 1024 * 1024; /* default: 2 GiB */
+ int c;
block_input ();
fmem = emacs_fopen ("/proc/meminfo", "r");
if (fmem)
{
- unsigned long entry_value;
- char entry_name[20]; /* the longest I saw is 13+1 */
+ uintmax_t entry_value;
+ bool done;
+
+ do
+ switch (fscanf (fmem, "MemTotal: %"SCNuMAX, &entry_value))
+ {
+ case 1:
+ retval = entry_value;
+ done = 1;
+ break;
+
+ case 0:
+ while ((c = getc (fmem)) != EOF && c != '\n')
+ continue;
+ done = c == EOF;
+ break;
+
+ default:
+ done = 1;
+ break;
+ }
+ while (!done);
- while (!feof (fmem) && !ferror (fmem))
- {
- if (fscanf (fmem, "%s %lu kB\n", entry_name, &entry_value) >= 2
- && strcmp (entry_name, "MemTotal:") == 0)
- {
- retval = entry_value;
- break;
- }
- }
fclose (fmem);
}
unblock_input ();
unsigned long long u_time, s_time, cutime, cstime, start;
long priority, niceness, rss;
unsigned long minflt, majflt, cminflt, cmajflt, vsize;
- EMACS_TIME tnow, tstart, tboot, telapsed, us_time;
+ struct timespec tnow, tstart, tboot, telapsed, us_time;
double pcpu, pmem;
Lisp_Object attrs = Qnil;
Lisp_Object cmd_str, decoded_cmd;
attrs = Fcons (Fcons (Qnice, make_number (niceness)), attrs);
attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (thcount)),
attrs);
- tnow = current_emacs_time ();
+ tnow = current_timespec ();
telapsed = get_up_time ();
- tboot = sub_emacs_time (tnow, telapsed);
+ tboot = timespec_sub (tnow, telapsed);
tstart = time_from_jiffies (start, clocks_per_sec);
- tstart = add_emacs_time (tboot, tstart);
+ tstart = timespec_add (tboot, tstart);
attrs = Fcons (Fcons (Qstart, make_lisp_time (tstart)), attrs);
attrs = Fcons (Fcons (Qvsize, make_fixnum_or_float (vsize / 1024)),
attrs);
attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (4 * rss)), attrs);
- telapsed = sub_emacs_time (tnow, tstart);
+ telapsed = timespec_sub (tnow, tstart);
attrs = Fcons (Fcons (Qetime, make_lisp_time (telapsed)), attrs);
us_time = time_from_jiffies (u_time + s_time, clocks_per_sec);
- pcpu = (EMACS_TIME_TO_DOUBLE (us_time)
- / EMACS_TIME_TO_DOUBLE (telapsed));
+ pcpu = timespectod (us_time) / timespectod (telapsed);
if (pcpu > 1.0)
pcpu = 1.0;
attrs = Fcons (Fcons (Qpcpu, make_float (100 * pcpu)), attrs);
#elif defined __FreeBSD__
-static EMACS_TIME
-timeval_to_EMACS_TIME (struct timeval t)
+static struct timespec
+timeval_to_timespec (struct timeval t)
{
- return make_emacs_time (t.tv_sec, t.tv_usec * 1000);
+ return make_timespec (t.tv_sec, t.tv_usec * 1000);
}
static Lisp_Object
make_lisp_timeval (struct timeval t)
{
- return make_lisp_time (timeval_to_EMACS_TIME (t));
+ return make_lisp_time (timeval_to_timespec (t));
}
Lisp_Object
{
int proc_id;
int pagesize = getpagesize ();
- int npages;
+ unsigned long npages;
int fscale;
struct passwd *pw;
struct group *gr;
char *ttyname;
size_t len;
char args[MAXPATHLEN];
- EMACS_TIME t, now;
+ struct timespec t, now;
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID};
struct kinfo_proc proc;
attrs);
attrs = Fcons (Fcons (Qstime, make_lisp_timeval (proc.ki_rusage.ru_stime)),
attrs);
- t = add_emacs_time (timeval_to_EMACS_TIME (proc.ki_rusage.ru_utime),
- timeval_to_EMACS_TIME (proc.ki_rusage.ru_stime));
+ t = timespec_add (timeval_to_timespec (proc.ki_rusage.ru_utime),
+ timeval_to_timespec (proc.ki_rusage.ru_stime));
attrs = Fcons (Fcons (Qtime, make_lisp_time (t)), attrs);
attrs = Fcons (Fcons (Qcutime,
attrs = Fcons (Fcons (Qcstime,
make_lisp_timeval (proc.ki_rusage_ch.ru_utime)),
attrs);
- t = add_emacs_time (timeval_to_EMACS_TIME (proc.ki_rusage_ch.ru_utime),
- timeval_to_EMACS_TIME (proc.ki_rusage_ch.ru_stime));
+ t = timespec_add (timeval_to_timespec (proc.ki_rusage_ch.ru_utime),
+ timeval_to_timespec (proc.ki_rusage_ch.ru_stime));
attrs = Fcons (Fcons (Qctime, make_lisp_time (t)), attrs);
attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (proc.ki_numthreads)),
attrs = Fcons (Fcons (Qrss, make_number (proc.ki_rssize * pagesize >> 10)),
attrs);
- now = current_emacs_time ();
- t = sub_emacs_time (now, timeval_to_EMACS_TIME (proc.ki_start));
+ now = current_timespec ();
+ t = timespec_sub (now, timeval_to_timespec (proc.ki_start));
attrs = Fcons (Fcons (Qetime, make_lisp_time (t)), attrs);
len = sizeof fscale;
}
#endif /* !defined (WINDOWSNT) */
+\f
+/* Wide character string collation. */
+
+#ifdef __STDC_ISO_10646__
+# include <wchar.h>
+# include <wctype.h>
+
+# if defined HAVE_NEWLOCALE || defined HAVE_SETLOCALE
+# include <locale.h>
+# endif
+# ifndef LC_COLLATE
+# define LC_COLLATE 0
+# endif
+# ifndef LC_COLLATE_MASK
+# define LC_COLLATE_MASK 0
+# endif
+# ifndef LC_CTYPE
+# define LC_CTYPE 0
+# endif
+# ifndef LC_CTYPE_MASK
+# define LC_CTYPE_MASK 0
+# endif
+
+# ifndef HAVE_NEWLOCALE
+# undef freelocale
+# undef locale_t
+# undef newlocale
+# undef wcscoll_l
+# undef towlower_l
+# define freelocale emacs_freelocale
+# define locale_t emacs_locale_t
+# define newlocale emacs_newlocale
+# define wcscoll_l emacs_wcscoll_l
+# define towlower_l emacs_towlower_l
+
+typedef char const *locale_t;
+
+static locale_t
+newlocale (int category_mask, char const *locale, locale_t loc)
+{
+ return locale;
+}
+
+static void
+freelocale (locale_t loc)
+{
+}
+
+static char *
+emacs_setlocale (int category, char const *locale)
+{
+# ifdef HAVE_SETLOCALE
+ errno = 0;
+ char *loc = setlocale (category, locale);
+ if (loc || errno)
+ return loc;
+ errno = EINVAL;
+# else
+ errno = ENOTSUP;
+# endif
+ return 0;
+}
+
+static int
+wcscoll_l (wchar_t const *a, wchar_t const *b, locale_t loc)
+{
+ int result = 0;
+ char *oldloc = emacs_setlocale (LC_COLLATE, NULL);
+ int err;
+
+ if (! oldloc)
+ err = errno;
+ else
+ {
+ USE_SAFE_ALLOCA;
+ char *oldcopy = SAFE_ALLOCA (strlen (oldloc) + 1);
+ strcpy (oldcopy, oldloc);
+ if (! emacs_setlocale (LC_COLLATE, loc))
+ err = errno;
+ else
+ {
+ errno = 0;
+ result = wcscoll (a, b);
+ err = errno;
+ if (! emacs_setlocale (LC_COLLATE, oldcopy))
+ err = errno;
+ }
+ SAFE_FREE ();
+ }
+
+ errno = err;
+ return result;
+}
+
+static wint_t
+towlower_l (wint_t wc, locale_t loc)
+{
+ wint_t result = wc;
+ char *oldloc = emacs_setlocale (LC_CTYPE, NULL);
+
+ if (oldloc)
+ {
+ USE_SAFE_ALLOCA;
+ char *oldcopy = SAFE_ALLOCA (strlen (oldloc) + 1);
+ strcpy (oldcopy, oldloc);
+ if (emacs_setlocale (LC_CTYPE, loc))
+ {
+ result = towlower (wc);
+ emacs_setlocale (LC_COLLATE, oldcopy);
+ }
+ SAFE_FREE ();
+ }
+
+ return result;
+}
+# endif
+
+int
+str_collate (Lisp_Object s1, Lisp_Object s2,
+ Lisp_Object locale, Lisp_Object ignore_case)
+{
+ int res, err;
+ ptrdiff_t len, i, i_byte;
+ wchar_t *p1, *p2;
+
+ USE_SAFE_ALLOCA;
+
+ /* Convert byte stream to code points. */
+ len = SCHARS (s1); i = i_byte = 0;
+ SAFE_NALLOCA (p1, 1, len + 1);
+ while (i < len)
+ FETCH_STRING_CHAR_ADVANCE (*(p1+i-1), s1, i, i_byte);
+ *(p1+len) = 0;
+
+ len = SCHARS (s2); i = i_byte = 0;
+ SAFE_NALLOCA (p2, 1, len + 1);
+ while (i < len)
+ FETCH_STRING_CHAR_ADVANCE (*(p2+i-1), s2, i, i_byte);
+ *(p2+len) = 0;
+
+ if (STRINGP (locale))
+ {
+ locale_t loc = newlocale (LC_COLLATE_MASK | LC_CTYPE_MASK,
+ SSDATA (locale), 0);
+ if (!loc)
+ error ("Invalid locale %s: %s", SSDATA (locale), strerror (errno));
+
+ if (! NILP (ignore_case))
+ for (int i = 1; i < 3; i++)
+ {
+ wchar_t *p = (i == 1) ? p1 : p2;
+ for (; *p; p++)
+ *p = towlower_l (*p, loc);
+ }
+
+ errno = 0;
+ res = wcscoll_l (p1, p2, loc);
+ err = errno;
+ freelocale (loc);
+ }
+ else
+ {
+ if (! NILP (ignore_case))
+ for (int i = 1; i < 3; i++)
+ {
+ wchar_t *p = (i == 1) ? p1 : p2;
+ for (; *p; p++)
+ *p = towlower (*p);
+ }
+
+ errno = 0;
+ res = wcscoll (p1, p2);
+ err = errno;
+ }
+# ifndef HAVE_NEWLOCALE
+ if (err)
+ error ("Invalid locale or string for collation: %s", strerror (err));
+# else
+ if (err)
+ error ("Invalid string for collation: %s", strerror (err));
+# endif
+
+ SAFE_FREE ();
+ return res;
+}
+#endif /* __STDC_ISO_10646__ */
+
+#ifdef WINDOWSNT
+int
+str_collate (Lisp_Object s1, Lisp_Object s2,
+ Lisp_Object locale, Lisp_Object ignore_case)
+{
+
+ char *loc = STRINGP (locale) ? SSDATA (locale) : NULL;
+ int res, err = errno;
+
+ errno = 0;
+ res = w32_compare_strings (SDATA (s1), SDATA (s2), loc, !NILP (ignore_case));
+ if (errno)
+ error ("Invalid string for collation: %s", strerror (errno));
+
+ errno = err;
+ return res;
+}
+#endif /* WINDOWSNT */