/* Asynchronous subprocess control for GNU Emacs.
- Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995,
- 1996, 1998, 1999, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+Copyright (C) 1985-1988, 1993-1996, 1998-1999, 2001-2011
+ Free Software Foundation, Inc.
This file is part of GNU Emacs.
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
-#ifdef STDC_HEADERS
-#include <stdlib.h>
-#endif
-#ifdef HAVE_UNISTD_H
#include <unistd.h>
-#endif
#include <fcntl.h>
/* Only MS-DOS does not define `subprocesses'. */
#endif
#endif
-#if defined(HAVE_SYS_IOCTL_H)
#include <sys/ioctl.h>
-#if !defined (O_NDELAY) && defined (HAVE_PTYS) && !defined(USG5)
-#include <fcntl.h>
-#endif /* HAVE_PTYS and no O_NDELAY */
#if defined(HAVE_NET_IF_H)
#include <net/if.h>
#endif /* HAVE_NET_IF_H */
-#endif /* HAVE_SYS_IOCTL_H */
#ifdef NEED_BSDTTY
#include <bsdtty.h>
#endif
-#ifdef HAVE_SYS_WAIT
-#include <sys/wait.h>
-#endif
-
#ifdef HAVE_RES_INIT
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <util.h>
#endif
+#ifdef HAVE_PTY_H
+#include <pty.h>
+#endif
+
#endif /* subprocesses */
#include "lisp.h"
#include "sysselect.h"
#include "syssignal.h"
#include "syswait.h"
+#ifdef HAVE_GNUTLS
+#include "gnutls.h"
+#endif
#if defined (USE_GTK) || defined (HAVE_GCONF)
#include "xgselect.h"
#ifdef HAVE_NS
#include "nsterm.h"
#endif
-extern int timers_run;
Lisp_Object Qeuid, Qegid, Qcomm, Qstate, Qppid, Qpgrp, Qsess, Qttname, Qtpgid;
Lisp_Object Qminflt, Qmajflt, Qcminflt, Qcmajflt, Qutime, Qstime, Qcstime;
static int kbd_is_on_hold;
-/* Nonzero means delete a process right away if it exits. */
-static int delete_exited_processes;
-
/* Nonzero means don't run process sentinels. This is used
when exiting. */
int inhibit_sentinels;
#ifdef subprocesses
-Lisp_Object Qprocessp;
-Lisp_Object Qrun, Qstop, Qsignal;
-Lisp_Object Qopen, Qclosed, Qconnect, Qfailed, Qlisten;
-Lisp_Object Qlocal, Qipv4, Qdatagram, Qseqpacket;
-Lisp_Object Qreal, Qnetwork, Qserial;
+static Lisp_Object Qprocessp;
+static Lisp_Object Qrun, Qstop, Qsignal;
+static Lisp_Object Qopen, Qclosed, Qconnect, Qfailed, Qlisten;
+Lisp_Object Qlocal;
+static Lisp_Object Qipv4, Qdatagram, Qseqpacket;
+static Lisp_Object Qreal, Qnetwork, Qserial;
#ifdef AF_INET6
-Lisp_Object Qipv6;
+static Lisp_Object Qipv6;
#endif
-Lisp_Object QCport, QCspeed, QCprocess;
+static Lisp_Object QCport, QCprocess;
+Lisp_Object QCspeed;
Lisp_Object QCbytesize, QCstopbits, QCparity, Qodd, Qeven;
Lisp_Object QCflowcontrol, Qhw, Qsw, QCsummary;
-Lisp_Object QCbuffer, QChost, QCservice;
-Lisp_Object QClocal, QCremote, QCcoding;
-Lisp_Object QCserver, QCnowait, QCnoquery, QCstop;
-Lisp_Object QCsentinel, QClog, QCoptions, QCplist;
-Lisp_Object Qlast_nonmenu_event;
+static Lisp_Object QCbuffer, QChost, QCservice;
+static Lisp_Object QClocal, QCremote, QCcoding;
+static Lisp_Object QCserver, QCnowait, QCnoquery, QCstop;
+static Lisp_Object QCsentinel, QClog, QCoptions, QCplist;
+static Lisp_Object Qlast_nonmenu_event;
/* QCfamily is declared and initialized in xfaces.c,
QCfilter in keyboard.c. */
extern Lisp_Object QCfamily, QCfilter;
#define SERIALCONN_P(p) (EQ (XPROCESS (p)->type, Qserial))
#define SERIALCONN1_P(p) (EQ ((p)->type, Qserial))
-/* Define first descriptor number available for subprocesses. */
-#define FIRST_PROC_DESC 3
-
-/* Define SIGCHLD as an alias for SIGCLD. There are many conditionals
- testing SIGCHLD. */
-
-#if !defined (SIGCHLD) && defined (SIGCLD)
-#define SIGCHLD SIGCLD
-#endif /* SIGCLD */
-
-extern const char *get_operating_system_release (void);
-
-/* Serial processes require termios or Windows. */
-#if defined (HAVE_TERMIOS) || defined (WINDOWSNT)
-#define HAVE_SERIAL
-#endif
-
-#ifdef HAVE_SERIAL
-/* From sysdep.c or w32.c */
-extern int serial_open (char *port);
-extern void serial_configure (struct Lisp_Process *p, Lisp_Object contact);
-#endif
-
#ifndef HAVE_H_ERRNO
extern int h_errno;
#endif
-/* t means use pty, nil means use a pipe,
- maybe other values to come. */
-static Lisp_Object Vprocess_connection_type;
-
-/* These next two vars are non-static since sysdep.c uses them in the
- emulation of `select'. */
/* Number of events of change of status of a process. */
-int process_tick;
+static int process_tick;
/* Number of events for which the user or sentinel has been notified. */
-int update_tick;
+static int update_tick;
/* Define NON_BLOCKING_CONNECT if we can support non-blocking connects. */
+/* Only W32 has this, it really means that select can't take write mask. */
#ifdef BROKEN_NON_BLOCKING_CONNECT
#undef NON_BLOCKING_CONNECT
+#define SELECT_CANT_DO_WRITE_MASK
#else
#ifndef NON_BLOCKING_CONNECT
#ifdef HAVE_SELECT
static int process_output_skip;
-/* Non-nil means to delay reading process output to improve buffering.
- A value of t means that delay is reset after each send, any other
- non-nil value does not reset the delay. A value of nil disables
- adaptive read buffering completely. */
-static Lisp_Object Vprocess_adaptive_read_buffering;
#else
#define process_output_delay_count 0
#endif
+INFUN (Fget_process, 1);
+static void create_process (Lisp_Object, char **, Lisp_Object);
static int keyboard_bit_set (SELECT_TYPE *);
static void deactivate_process (Lisp_Object);
static void status_notify (struct Lisp_Process *);
static SELECT_TYPE non_process_wait_mask;
-/* Mask for the gpm mouse input descriptor. */
+/* Mask for selecting for write. */
-static SELECT_TYPE gpm_wait_mask;
+static SELECT_TYPE write_mask;
#ifdef NON_BLOCKING_CONNECT
/* Mask of bits indicating the descriptors that we wait for connect to
/* Number of bits set in connect_wait_mask. */
static int num_pending_connects;
-
-#define IF_NON_BLOCKING_CONNECT(s) s
-#else /* NON_BLOCKING_CONNECT */
-#define IF_NON_BLOCKING_CONNECT(s)
#endif /* NON_BLOCKING_CONNECT */
/* The largest descriptor currently in use for a process object. */
static int max_process_desc;
-/* The largest descriptor currently in use for keyboard input. */
-static int max_keyboard_desc;
-
-/* The largest descriptor currently in use for gpm mouse input. */
-static int max_gpm_desc;
+/* The largest descriptor currently in use for input. */
+static int max_input_desc;
/* Indexed by descriptor, gives the process (if any) for that descriptor */
-Lisp_Object chan_process[MAXDESC];
+static Lisp_Object chan_process[MAXDESC];
/* Alist of elements (NAME . PROCESS) */
-Lisp_Object Vprocess_alist;
+static Lisp_Object Vprocess_alist;
/* Buffered-ahead input char from process, indexed by channel.
-1 means empty (no char is buffered).
output from the process is to read at least one char.
Always -1 on systems that support FIONREAD. */
-/* Don't make static; need to access externally. */
-int proc_buffered_char[MAXDESC];
+static int proc_buffered_char[MAXDESC];
/* Table of `struct coding-system' for each process. */
static struct coding_system *proc_decode_coding_system[MAXDESC];
#ifdef DATAGRAM_SOCKETS
/* Table of `partner address' for datagram sockets. */
-struct sockaddr_and_len {
+static struct sockaddr_and_len {
struct sockaddr *sa;
int len;
} datagram_address[MAXDESC];
/* Maximum number of bytes to send to a pty without an eof. */
static int pty_max_bytes;
-#ifdef HAVE_PTYS
-#ifdef HAVE_PTY_H
-#include <pty.h>
-#endif
-/* The file name of the pty opened by allocate_pty. */
+\f
+
+static struct fd_callback_data
+{
+ fd_callback func;
+ void *data;
+#define FOR_READ 1
+#define FOR_WRITE 2
+ int condition; /* mask of the defines above. */
+} fd_callback_info[MAXDESC];
+
+
+/* Add a file descriptor FD to be monitored for when read is possible.
+ When read is possible, call FUNC with argument DATA. */
+
+void
+add_read_fd (int fd, fd_callback func, void *data)
+{
+ xassert (fd < MAXDESC);
+ add_keyboard_wait_descriptor (fd);
+
+ fd_callback_info[fd].func = func;
+ fd_callback_info[fd].data = data;
+ fd_callback_info[fd].condition |= FOR_READ;
+}
+
+/* Stop monitoring file descriptor FD for when read is possible. */
+
+void
+delete_read_fd (int fd)
+{
+ xassert (fd < MAXDESC);
+ delete_keyboard_wait_descriptor (fd);
+
+ fd_callback_info[fd].condition &= ~FOR_READ;
+ if (fd_callback_info[fd].condition == 0)
+ {
+ fd_callback_info[fd].func = 0;
+ fd_callback_info[fd].data = 0;
+ }
+}
+
+/* Add a file descriptor FD to be monitored for when write is possible.
+ When write is possible, call FUNC with argument DATA. */
+
+void
+add_write_fd (int fd, fd_callback func, void *data)
+{
+ xassert (fd < MAXDESC);
+ FD_SET (fd, &write_mask);
+ if (fd > max_input_desc)
+ max_input_desc = fd;
+
+ fd_callback_info[fd].func = func;
+ fd_callback_info[fd].data = data;
+ fd_callback_info[fd].condition |= FOR_WRITE;
+}
+
+/* Stop monitoring file descriptor FD for when write is possible. */
+
+void
+delete_write_fd (int fd)
+{
+ int lim = max_input_desc;
+
+ xassert (fd < MAXDESC);
+ FD_CLR (fd, &write_mask);
+ fd_callback_info[fd].condition &= ~FOR_WRITE;
+ if (fd_callback_info[fd].condition == 0)
+ {
+ fd_callback_info[fd].func = 0;
+ fd_callback_info[fd].data = 0;
+
+ if (fd == max_input_desc)
+ for (fd = lim; fd >= 0; fd--)
+ if (FD_ISSET (fd, &input_wait_mask) || FD_ISSET (fd, &write_mask))
+ {
+ max_input_desc = fd;
+ break;
+ }
+
+ }
+}
-static char pty_name[24];
-#endif
\f
/* Compute the Lisp form of the process status, p->status, from
the numeric status that was returned by `wait'. */
if (! NILP (Vlocale_coding_system))
string = (code_convert_string_norecord
(string, Vlocale_coding_system, 0));
- c1 = STRING_CHAR ((char *) SDATA (string));
- c2 = DOWNCASE (c1);
+ c1 = STRING_CHAR (SDATA (string));
+ c2 = downcase (c1);
if (c1 != c2)
Faset (string, make_number (0), make_number (c2));
}
\f
#ifdef HAVE_PTYS
+/* The file name of the pty opened by allocate_pty. */
+static char pty_name[24];
+
/* Open an available pty, returning a file descriptor.
Return -1 on failure.
The file name of the terminal corresponding to the pty
static int
allocate_pty (void)
{
- register int c, i;
int fd;
#ifdef PTY_ITERATION
PTY_ITERATION
#else
+ register int c, i;
for (c = FIRST_PTY_LETTER; c <= 'z'; c++)
for (i = 0; i < 16; i++)
#endif
{
- struct stat stb; /* Used in some PTY_OPEN. */
#ifdef PTY_NAME_SPRINTF
PTY_NAME_SPRINTF
#else
three failures in a row before deciding that we've reached the
end of the ptys. */
int failed_count = 0;
+ struct stat stb;
if (stat (pty_name, &stb) < 0)
{
p->read_output_skip = 0;
#endif
+#ifdef HAVE_GNUTLS
+ p->gnutls_initstage = GNUTLS_STAGE_EMPTY;
+ p->gnutls_log_level = 0;
+ p->gnutls_p = 0;
+#endif
+
/* If name is already in use, modify it until it is unused. */
name1 = name;
{
proc = Fget_buffer_process (obj);
if (NILP (proc))
- error ("Buffer %s has no process", SDATA (XBUFFER (obj)->name));
+ error ("Buffer %s has no process", SDATA (BVAR (XBUFFER (obj), name)));
}
else
{
}
#ifdef DATAGRAM_SOCKETS
-Lisp_Object Fprocess_datagram_address (Lisp_Object process);
+INFUN (Fprocess_datagram_address, 1);
#endif
DEFUN ("process-contact", Fprocess_contact, Sprocess_contact,
return Qnil;
}
-\f
-static Lisp_Object
-list_processes_1 (Lisp_Object query_only)
-{
- register Lisp_Object tail, tem;
- Lisp_Object proc, minspace, tem1;
- register struct Lisp_Process *p;
- char tembuf[300];
- int w_proc, w_buffer, w_tty;
- int exited = 0;
- Lisp_Object i_status, i_buffer, i_tty, i_command;
-
- w_proc = 4; /* Proc */
- w_buffer = 6; /* Buffer */
- w_tty = 0; /* Omit if no ttys */
-
- for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
- {
- int i;
-
- proc = Fcdr (XCAR (tail));
- p = XPROCESS (proc);
- if (NILP (p->type))
- continue;
- if (!NILP (query_only) && p->kill_without_query)
- continue;
- if (STRINGP (p->name)
- && ( i = SCHARS (p->name), (i > w_proc)))
- w_proc = i;
- if (!NILP (p->buffer))
- {
- if (NILP (XBUFFER (p->buffer)->name))
- {
- if (w_buffer < 8)
- w_buffer = 8; /* (Killed) */
- }
- else if ((i = SCHARS (XBUFFER (p->buffer)->name), (i > w_buffer)))
- w_buffer = i;
- }
- if (STRINGP (p->tty_name)
- && (i = SCHARS (p->tty_name), (i > w_tty)))
- w_tty = i;
- }
-
- XSETFASTINT (i_status, w_proc + 1);
- XSETFASTINT (i_buffer, XFASTINT (i_status) + 9);
- if (w_tty)
- {
- XSETFASTINT (i_tty, XFASTINT (i_buffer) + w_buffer + 1);
- XSETFASTINT (i_command, XFASTINT (i_tty) + w_tty + 1);
- }
- else
- {
- i_tty = Qnil;
- XSETFASTINT (i_command, XFASTINT (i_buffer) + w_buffer + 1);
- }
-
- XSETFASTINT (minspace, 1);
-
- set_buffer_internal (XBUFFER (Vstandard_output));
- current_buffer->undo_list = Qt;
-
- current_buffer->truncate_lines = Qt;
-
- write_string ("Proc", -1);
- Findent_to (i_status, minspace); write_string ("Status", -1);
- Findent_to (i_buffer, minspace); write_string ("Buffer", -1);
- if (!NILP (i_tty))
- {
- Findent_to (i_tty, minspace); write_string ("Tty", -1);
- }
- Findent_to (i_command, minspace); write_string ("Command", -1);
- write_string ("\n", -1);
-
- write_string ("----", -1);
- Findent_to (i_status, minspace); write_string ("------", -1);
- Findent_to (i_buffer, minspace); write_string ("------", -1);
- if (!NILP (i_tty))
- {
- Findent_to (i_tty, minspace); write_string ("---", -1);
- }
- Findent_to (i_command, minspace); write_string ("-------", -1);
- write_string ("\n", -1);
-
- for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
- {
- Lisp_Object symbol;
-
- proc = Fcdr (XCAR (tail));
- p = XPROCESS (proc);
- if (NILP (p->type))
- continue;
- if (!NILP (query_only) && p->kill_without_query)
- continue;
-
- Finsert (1, &p->name);
- Findent_to (i_status, minspace);
-
- if (p->raw_status_new)
- update_status (p);
- symbol = p->status;
- if (CONSP (p->status))
- symbol = XCAR (p->status);
-
- if (EQ (symbol, Qsignal))
- {
- Lisp_Object tem;
- tem = Fcar (Fcdr (p->status));
- Fprinc (symbol, Qnil);
- }
- else if (NETCONN1_P (p) || SERIALCONN1_P (p))
- {
- if (EQ (symbol, Qexit))
- write_string ("closed", -1);
- else if (EQ (p->command, Qt))
- write_string ("stopped", -1);
- else if (EQ (symbol, Qrun))
- write_string ("open", -1);
- else
- Fprinc (symbol, Qnil);
- }
- else if (SERIALCONN1_P (p))
- {
- write_string ("running", -1);
- }
- else
- Fprinc (symbol, Qnil);
-
- if (EQ (symbol, Qexit))
- {
- Lisp_Object tem;
- tem = Fcar (Fcdr (p->status));
- if (XFASTINT (tem))
- {
- sprintf (tembuf, " %d", (int) XFASTINT (tem));
- write_string (tembuf, -1);
- }
- }
-
- if (EQ (symbol, Qsignal) || EQ (symbol, Qexit) || EQ (symbol, Qclosed))
- exited++;
-
- Findent_to (i_buffer, minspace);
- if (NILP (p->buffer))
- insert_string ("(none)");
- else if (NILP (XBUFFER (p->buffer)->name))
- insert_string ("(Killed)");
- else
- Finsert (1, &XBUFFER (p->buffer)->name);
-
- if (!NILP (i_tty))
- {
- Findent_to (i_tty, minspace);
- if (STRINGP (p->tty_name))
- Finsert (1, &p->tty_name);
- }
-
- Findent_to (i_command, minspace);
-
- if (EQ (p->status, Qlisten))
- {
- Lisp_Object port = Fplist_get (p->childp, QCservice);
- if (INTEGERP (port))
- port = Fnumber_to_string (port);
- if (NILP (port))
- port = Fformat_network_address (Fplist_get (p->childp, QClocal), Qnil);
- sprintf (tembuf, "(network %s server on %s)\n",
- (DATAGRAM_CHAN_P (p->infd) ? "datagram" : "stream"),
- (STRINGP (port) ? (char *)SDATA (port) : "?"));
- insert_string (tembuf);
- }
- else if (NETCONN1_P (p))
- {
- /* For a local socket, there is no host name,
- so display service instead. */
- Lisp_Object host = Fplist_get (p->childp, QChost);
- if (!STRINGP (host))
- {
- host = Fplist_get (p->childp, QCservice);
- if (INTEGERP (host))
- host = Fnumber_to_string (host);
- }
- if (NILP (host))
- host = Fformat_network_address (Fplist_get (p->childp, QCremote), Qnil);
- sprintf (tembuf, "(network %s connection to %s)\n",
- (DATAGRAM_CHAN_P (p->infd) ? "datagram" : "stream"),
- (STRINGP (host) ? (char *)SDATA (host) : "?"));
- insert_string (tembuf);
- }
- else if (SERIALCONN1_P (p))
- {
- Lisp_Object port = Fplist_get (p->childp, QCport);
- Lisp_Object speed = Fplist_get (p->childp, QCspeed);
- insert_string ("(serial port ");
- if (STRINGP (port))
- insert_string (SDATA (port));
- else
- insert_string ("?");
- if (INTEGERP (speed))
- {
- sprintf (tembuf, " at %ld b/s", (long) XINT (speed));
- insert_string (tembuf);
- }
- insert_string (")\n");
- }
- else
- {
- tem = p->command;
- while (1)
- {
- tem1 = Fcar (tem);
- if (NILP (tem1))
- break;
- Finsert (1, &tem1);
- tem = Fcdr (tem);
- if (NILP (tem))
- break;
- insert_string (" ");
- }
- insert_string ("\n");
- }
- }
- if (exited)
- {
- status_notify (NULL);
- redisplay_preserve_echo_area (13);
- }
- return Qnil;
-}
-
-DEFUN ("list-processes", Flist_processes, Slist_processes, 0, 1, "P",
- doc: /* Display a list of all processes.
-If optional argument QUERY-ONLY is non-nil, only processes with
-the query-on-exit flag set will be listed.
-Any process listed as exited or signaled is actually eliminated
-after the listing is made. */)
- (Lisp_Object query_only)
-{
- internal_with_output_to_temp_buffer ("*Process List*",
- list_processes_1, query_only);
- return Qnil;
-}
DEFUN ("process-list", Fprocess_list, Sprocess_list, 0, 0, 0,
doc: /* Return a list of all processes. */)
function to handle the output. BUFFER may also be nil, meaning that
this process is not associated with any buffer.
-PROGRAM is the program file name. It is searched for in PATH. If
-nil, just associate a pty with the buffer. Remaining arguments are
-strings to give program as arguments.
+PROGRAM is the program file name. It is searched for in `exec-path'
+(which see). If nil, just associate a pty with the buffer. Remaining
+arguments are strings to give program as arguments.
If you want to separate standard output from standard error, invoke
the command through a shell and redirect one of them using the shell
syntax.
usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */)
- (int nargs, register Lisp_Object *args)
+ (size_t nargs, register Lisp_Object *args)
{
Lisp_Object buffer, name, program, proc, current_dir, tem;
register unsigned char **new_argv;
- register int i;
+ register size_t i;
int count = SPECPDL_INDEX ();
buffer = args[1];
{
struct gcpro gcpro1, gcpro2;
- current_dir = current_buffer->directory;
+ current_dir = BVAR (current_buffer, directory);
GCPRO2 (buffer, current_dir);
current_dir = expand_and_dir_to_file (current_dir, Qnil);
if (NILP (Ffile_accessible_directory_p (current_dir)))
report_file_error ("Setting current directory",
- Fcons (current_buffer->directory, Qnil));
+ Fcons (BVAR (current_buffer, directory), Qnil));
UNGCPRO;
}
XPROCESS (proc)->filter = Qnil;
XPROCESS (proc)->command = Flist (nargs - 2, args + 2);
+#ifdef HAVE_GNUTLS
+ /* AKA GNUTLS_INITSTAGE(proc). */
+ XPROCESS (proc)->gnutls_initstage = GNUTLS_STAGE_EMPTY;
+ XPROCESS (proc)->gnutls_cred_type = Qnil;
+#endif
+
#ifdef ADAPTIVE_READ_BUFFERING
XPROCESS (proc)->adaptive_read_buffering
= (NILP (Vprocess_adaptive_read_buffering) ? 0
val = XCDR (Vdefault_process_coding_system);
}
XPROCESS (proc)->encode_coding_system = val;
+ /* Note: At this momemnt, the above coding system may leave
+ text-conversion or eol-conversion unspecified. They will be
+ decided after we read output from the process and decode it by
+ some coding system, or just before we actually send a text to
+ the process. */
}
- XPROCESS (proc)->decoding_buf = make_uninit_string (0);
+ XPROCESS (proc)->decoding_buf = empty_unibyte_string;
XPROCESS (proc)->decoding_carryover = 0;
- XPROCESS (proc)->encoding_buf = make_uninit_string (0);
+ XPROCESS (proc)->encoding_buf = empty_unibyte_string;
XPROCESS (proc)->inherit_coding_system_flag
= !(NILP (buffer) || !inherit_process_coding_system);
tem = Fsubstring (tem, make_number (2), Qnil);
{
+ Lisp_Object arg_encoding = Qnil;
struct gcpro gcpro1;
GCPRO1 (tem);
tem = Fcons (args[i], tem);
CHECK_STRING (XCAR (tem));
if (STRING_MULTIBYTE (XCAR (tem)))
- XSETCAR (tem,
- code_convert_string_norecord
- (XCAR (tem), XPROCESS (proc)->encode_coding_system, 1));
+ {
+ if (NILP (arg_encoding))
+ arg_encoding = (complement_process_encoding_system
+ (XPROCESS (proc)->encode_coding_system));
+ XSETCAR (tem,
+ code_convert_string_norecord
+ (XCAR (tem), arg_encoding, 1));
+ }
}
UNGCPRO;
new_argv = (unsigned char **) alloca ((nargs - 1) * sizeof (char *));
new_argv[nargs - 2] = 0;
- for (i = nargs - 3; i >= 0; i--)
+ for (i = nargs - 2; i-- != 0; )
{
new_argv[i] = SDATA (XCAR (tem));
tem = XCDR (tem);
}
-void
+static void
create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
{
int inchannel, outchannel;
sigset_t blocked;
struct sigaction sigint_action;
struct sigaction sigquit_action;
+ struct sigaction sigpipe_action;
#ifdef AIX
struct sigaction sighup_action;
#endif
}
#endif
-#if 0
- /* Replaced by close_process_descs */
- set_exclusive_use (inchannel);
- set_exclusive_use (outchannel);
-#endif
-
#ifdef O_NONBLOCK
fcntl (inchannel, F_SETFL, O_NONBLOCK);
fcntl (outchannel, F_SETFL, O_NONBLOCK);
and record the current handlers so they can be restored later. */
sigaddset (&blocked, SIGINT ); sigaction (SIGINT , 0, &sigint_action );
sigaddset (&blocked, SIGQUIT); sigaction (SIGQUIT, 0, &sigquit_action);
+ sigaddset (&blocked, SIGPIPE); sigaction (SIGPIPE, 0, &sigpipe_action);
#ifdef AIX
sigaddset (&blocked, SIGHUP ); sigaction (SIGHUP , 0, &sighup_action );
#endif
/* child_setup must clobber environ on systems with true vfork.
Protect it from permanent change. */
char **save_environ = environ;
-
- current_dir = ENCODE_FILE (current_dir);
+ volatile Lisp_Object encoded_current_dir = ENCODE_FILE (current_dir);
#ifndef WINDOWSNT
pid = vfork ();
setpgrp ();
#endif /* USG */
#endif /* not HAVE_SETSID */
-#if defined (HAVE_TERMIOS) && defined (LDISC1)
+#if defined (LDISC1)
if (pty_flag && xforkin >= 0)
{
struct termios t;
signal (SIGINT, SIG_DFL);
signal (SIGQUIT, SIG_DFL);
+ /* GConf causes us to ignore SIGPIPE, make sure it is restored
+ in the child. */
+ signal (SIGPIPE, SIG_DFL);
/* Stop blocking signals in the child. */
sigprocmask (SIG_SETMASK, &procmask, 0);
child_setup_tty (xforkout);
#ifdef WINDOWSNT
pid = child_setup (xforkin, xforkout, xforkout,
- new_argv, 1, current_dir);
+ new_argv, 1, encoded_current_dir);
#else /* not WINDOWSNT */
#ifdef FD_CLOEXEC
emacs_close (wait_child_setup[0]);
#endif
child_setup (xforkin, xforkout, xforkout,
- new_argv, 1, current_dir);
+ new_argv, 1, encoded_current_dir);
#endif /* not WINDOWSNT */
}
environ = save_environ;
/* Restore the parent's signal handlers. */
sigaction (SIGINT, &sigint_action, 0);
sigaction (SIGQUIT, &sigquit_action, 0);
+ sigaction (SIGPIPE, &sigpipe_action, 0);
#ifdef AIX
sigaction (SIGHUP, &sighup_action, 0);
#endif
create_pty (Lisp_Object process)
{
int inchannel, outchannel;
-
- /* Use volatile to protect variables from being clobbered by longjmp. */
- volatile int forkin, forkout;
- volatile int pty_flag = 0;
+ int pty_flag = 0;
inchannel = outchannel = -1;
#ifdef O_NOCTTY
/* Don't let this terminal become our controlling terminal
(in case we don't have one). */
- forkout = forkin = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
+ int forkout = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
#else
- forkout = forkin = emacs_open (pty_name, O_RDWR, 0);
+ int forkout = emacs_open (pty_name, O_RDWR, 0);
#endif
- if (forkin < 0)
+ if (forkout < 0)
report_file_error ("Opening pty", Qnil);
#if defined (DONT_REOPEN_PTY)
/* In the case that vfork is defined as fork, the parent process
tty options setup. So we setup tty before forking. */
child_setup_tty (forkout);
#endif /* DONT_REOPEN_PTY */
-#else
- forkin = forkout = -1;
#endif /* not USG, or USG_SUBTTY_WORKS */
pty_flag = 1;
}
CHECK_SYMBOL (opt);
- name = (char *) SDATA (SYMBOL_NAME (opt));
+ name = SSDATA (SYMBOL_NAME (opt));
for (sopt = socket_options; sopt->name; sopt++)
if (strcmp (name, sopt->name) == 0)
break;
memset (devname, 0, sizeof devname);
if (STRINGP (val))
{
- char *arg = (char *) SDATA (val);
+ char *arg = SSDATA (val);
int len = min (strlen (arg), IFNAMSIZ);
memcpy (devname, arg, len);
}
}
\f
-#ifdef HAVE_SERIAL
DEFUN ("serial-process-configure",
Fserial_process_configure,
Sserial_process_configure,
\(serial-process-configure :port "\\\\.\\COM13" :bytesize 7)
usage: (serial-process-configure &rest ARGS) */)
- (int nargs, Lisp_Object *args)
+ (size_t nargs, Lisp_Object *args)
{
struct Lisp_Process *p;
Lisp_Object contact = Qnil;
}
/* Used by make-serial-process to recover from errors. */
-Lisp_Object make_serial_process_unwind (Lisp_Object proc)
+static Lisp_Object
+make_serial_process_unwind (Lisp_Object proc)
{
if (!PROCESSP (proc))
abort ();
\(make-serial-process :port "/dev/tty.BlueConsole-SPP-1" :speed nil)
usage: (make-serial-process &rest ARGS) */)
- (int nargs, Lisp_Object *args)
+ (size_t nargs, Lisp_Object *args)
{
int fd = -1;
Lisp_Object proc, contact, port;
record_unwind_protect (make_serial_process_unwind, proc);
p = XPROCESS (proc);
- fd = serial_open ((char*) SDATA (port));
+ fd = serial_open (SSDATA (port));
p->infd = fd;
p->outfd = fd;
if (fd > max_process_desc)
}
else if (!NILP (Vcoding_system_for_read))
val = Vcoding_system_for_read;
- else if ((!NILP (buffer) && NILP (XBUFFER (buffer)->enable_multibyte_characters))
- || (NILP (buffer) && NILP (buffer_defaults.enable_multibyte_characters)))
+ else if ((!NILP (buffer) && NILP (BVAR (XBUFFER (buffer), enable_multibyte_characters)))
+ || (NILP (buffer) && NILP (BVAR (&buffer_defaults, enable_multibyte_characters))))
val = Qnil;
p->decode_coding_system = val;
}
else if (!NILP (Vcoding_system_for_write))
val = Vcoding_system_for_write;
- else if ((!NILP (buffer) && NILP (XBUFFER (buffer)->enable_multibyte_characters))
- || (NILP (buffer) && NILP (buffer_defaults.enable_multibyte_characters)))
+ else if ((!NILP (buffer) && NILP (BVAR (XBUFFER (buffer), enable_multibyte_characters)))
+ || (NILP (buffer) && NILP (BVAR (&buffer_defaults, enable_multibyte_characters))))
val = Qnil;
p->encode_coding_system = val;
setup_process_coding_systems (proc);
- p->decoding_buf = make_uninit_string (0);
+ p->decoding_buf = empty_unibyte_string;
p->decoding_carryover = 0;
- p->encoding_buf = make_uninit_string (0);
+ p->encoding_buf = empty_unibyte_string;
p->inherit_coding_system_flag
= !(!NILP (tem) || NILP (buffer) || !inherit_process_coding_system);
UNGCPRO;
return proc;
}
-#endif /* HAVE_SERIAL */
/* Create a network stream/datagram client/server process. Treated
exactly like a normal process when reading and writing. Primary
information, is available via the `process-contact' function.
usage: (make-network-process &rest ARGS) */)
- (int nargs, Lisp_Object *args)
+ (size_t nargs, Lisp_Object *args)
{
Lisp_Object proc;
Lisp_Object contact;
if (!NILP (host))
{
if (EQ (host, Qlocal))
- host = build_string ("localhost");
+ /* Depending on setup, "localhost" may map to different IPv4 and/or
+ IPv6 addresses, so it's better to be explicit. (Bug#6781) */
+ host = build_string ("127.0.0.1");
CHECK_STRING (host);
}
CHECK_STRING (service);
memset (&address_un, 0, sizeof address_un);
address_un.sun_family = AF_LOCAL;
- strncpy (address_un.sun_path, SDATA (service), sizeof address_un.sun_path);
+ strncpy (address_un.sun_path, SSDATA (service), sizeof address_un.sun_path);
ai.ai_addr = (struct sockaddr *) &address_un;
ai.ai_addrlen = sizeof address_un;
goto open_socket;
else
{
CHECK_STRING (service);
- portstring = SDATA (service);
+ portstring = SSDATA (service);
}
immediate_quit = 1;
res_init ();
#endif
- ret = getaddrinfo (SDATA (host), portstring, &hints, &res);
+ ret = getaddrinfo (SSDATA (host), portstring, &hints, &res);
if (ret)
#ifdef HAVE_GAI_STRERROR
- error ("%s/%s %s", SDATA (host), portstring, gai_strerror (ret));
+ error ("%s/%s %s", SSDATA (host), portstring, gai_strerror (ret));
#else
- error ("%s/%s getaddrinfo error %d", SDATA (host), portstring, ret);
+ error ("%s/%s getaddrinfo error %d", SSDATA (host), portstring, ret);
#endif
immediate_quit = 0;
{
struct servent *svc_info;
CHECK_STRING (service);
- svc_info = getservbyname (SDATA (service),
+ svc_info = getservbyname (SSDATA (service),
(socktype == SOCK_DGRAM ? "udp" : "tcp"));
if (svc_info == 0)
error ("Unknown service: %s", SDATA (service));
/* Attempt to interpret host as numeric inet address */
{
unsigned long numeric_addr;
- numeric_addr = inet_addr ((char *) SDATA (host));
+ numeric_addr = inet_addr (SSDATA (host));
if (numeric_addr == -1)
error ("Unknown host \"%s\"", SDATA (host));
for (lres = res; lres; lres = lres->ai_next)
{
- int optn, optbits;
+ size_t optn;
+ int optbits;
+#ifdef WINDOWSNT
retry_connect:
+#endif
s = socket (lres->ai_family, lres->ai_socktype, lres->ai_protocol);
if (s < 0)
if (EQ (service, Qt))
{
struct sockaddr_in sa1;
- int len1 = sizeof (sa1);
+ socklen_t len1 = sizeof (sa1);
if (getsockname (s, (struct sockaddr *)&sa1, &len1) == 0)
{
((struct sockaddr_in *)(lres->ai_addr))->sin_port = sa1.sin_port;
/* Unlike most other syscalls connect() cannot be called
again. (That would return EALREADY.) The proper way to
wait for completion is select(). */
- int sc, len;
+ int sc;
+ socklen_t len;
SELECT_TYPE fdset;
retry_select:
FD_ZERO (&fdset);
if (!is_server)
{
struct sockaddr_in sa1;
- int len1 = sizeof (sa1);
+ socklen_t len1 = sizeof (sa1);
if (getsockname (s, (struct sockaddr *)&sa1, &len1) == 0)
contact = Fplist_put (contact, QClocal,
conv_sockaddr_to_lisp ((struct sockaddr *)&sa1, len1));
if (!FD_ISSET (inch, &connect_wait_mask))
{
FD_SET (inch, &connect_wait_mask);
+ FD_SET (inch, &write_mask);
num_pending_connects++;
}
}
{
/* Setup coding systems for communicating with the network stream. */
- struct gcpro gcpro1;
+ struct gcpro inner_gcpro1;
/* Qt denotes we have not yet called Ffind_operation_coding_system. */
Lisp_Object coding_systems = Qt;
- Lisp_Object args[5], val;
+ Lisp_Object fargs[5], val;
if (!NILP (tem))
{
}
else if (!NILP (Vcoding_system_for_read))
val = Vcoding_system_for_read;
- else if ((!NILP (buffer) && NILP (XBUFFER (buffer)->enable_multibyte_characters))
- || (NILP (buffer) && NILP (buffer_defaults.enable_multibyte_characters)))
+ else if ((!NILP (buffer) && NILP (BVAR (XBUFFER (buffer), enable_multibyte_characters)))
+ || (NILP (buffer) && NILP (BVAR (&buffer_defaults, enable_multibyte_characters))))
/* We dare not decode end-of-line format by setting VAL to
Qraw_text, because the existing Emacs Lisp libraries
assume that they receive bare code including a sequene of
coding_systems = Qnil;
else
{
- args[0] = Qopen_network_stream, args[1] = name,
- args[2] = buffer, args[3] = host, args[4] = service;
- GCPRO1 (proc);
- coding_systems = Ffind_operation_coding_system (5, args);
- UNGCPRO;
+ fargs[0] = Qopen_network_stream, fargs[1] = name,
+ fargs[2] = buffer, fargs[3] = host, fargs[4] = service;
+ GCPRO1_VAR (proc, inner_gcpro);
+ coding_systems = Ffind_operation_coding_system (5, fargs);
+ UNGCPRO_VAR (inner_gcpro);
}
if (CONSP (coding_systems))
val = XCAR (coding_systems);
}
else if (!NILP (Vcoding_system_for_write))
val = Vcoding_system_for_write;
- else if (NILP (current_buffer->enable_multibyte_characters))
+ else if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
val = Qnil;
else
{
coding_systems = Qnil;
else
{
- args[0] = Qopen_network_stream, args[1] = name,
- args[2] = buffer, args[3] = host, args[4] = service;
- GCPRO1 (proc);
- coding_systems = Ffind_operation_coding_system (5, args);
- UNGCPRO;
+ fargs[0] = Qopen_network_stream, fargs[1] = name,
+ fargs[2] = buffer, fargs[3] = host, fargs[4] = service;
+ GCPRO1_VAR (proc, inner_gcpro);
+ coding_systems = Ffind_operation_coding_system (5, fargs);
+ UNGCPRO_VAR (inner_gcpro);
}
}
if (CONSP (coding_systems))
}
setup_process_coding_systems (proc);
- p->decoding_buf = make_uninit_string (0);
+ p->decoding_buf = empty_unibyte_string;
p->decoding_carryover = 0;
- p->encoding_buf = make_uninit_string (0);
+ p->encoding_buf = empty_unibyte_string;
p->inherit_coding_system_flag
= !(!NILP (tem) || NILP (buffer) || !inherit_process_coding_system);
}
\f
-#if defined(HAVE_NET_IF_H) && defined(HAVE_SYS_IOCTL_H)
+#if defined(HAVE_NET_IF_H)
#ifdef SIOCGIFCONF
DEFUN ("network-interface-list", Fnetwork_interface_list, Snetwork_interface_list, 0, 0, 0,
CHECK_STRING (ifname);
memset (rq.ifr_name, 0, sizeof rq.ifr_name);
- strncpy (rq.ifr_name, SDATA (ifname), sizeof (rq.ifr_name));
+ strncpy (rq.ifr_name, SSDATA (ifname), sizeof (rq.ifr_name));
s = socket (AF_INET, SOCK_STREAM, 0);
if (s < 0)
const struct ifflag_def *fp;
int fnum;
- any++;
+ any = 1;
for (fp = ifflag_table; flags != 0 && fp->flag_sym; fp++)
{
if (flags & fp->flag_bit)
register struct Lisp_Vector *p = XVECTOR (hwaddr);
int n;
- any++;
+ any = 1;
for (n = 0; n < 6; n++)
p->contents[n] = make_number (((unsigned char *)&rq.ifr_hwaddr.sa_data[0])[n]);
elt = Fcons (make_number (rq.ifr_hwaddr.sa_family), hwaddr);
#if defined(SIOCGIFNETMASK) && (defined(HAVE_STRUCT_IFREQ_IFR_NETMASK) || defined(HAVE_STRUCT_IFREQ_IFR_ADDR))
if (ioctl (s, SIOCGIFNETMASK, &rq) == 0)
{
- any++;
+ any = 1;
#ifdef HAVE_STRUCT_IFREQ_IFR_NETMASK
elt = conv_sockaddr_to_lisp (&rq.ifr_netmask, sizeof (rq.ifr_netmask));
#else
#if defined(SIOCGIFBRDADDR) && defined(HAVE_STRUCT_IFREQ_IFR_BROADADDR)
if (ioctl (s, SIOCGIFBRDADDR, &rq) == 0)
{
- any++;
+ any = 1;
elt = conv_sockaddr_to_lisp (&rq.ifr_broadaddr, sizeof (rq.ifr_broadaddr));
}
#endif
#if defined(SIOCGIFADDR) && defined(HAVE_STRUCT_IFREQ_IFR_ADDR)
if (ioctl (s, SIOCGIFADDR, &rq) == 0)
{
- any++;
+ any = 1;
elt = conv_sockaddr_to_lisp (&rq.ifr_addr, sizeof (rq.ifr_addr));
}
#endif
return any ? res : Qnil;
}
#endif
-#endif /* defined(HAVE_NET_IF_H) && defined(HAVE_SYS_IOCTL_H) */
+#endif /* defined(HAVE_NET_IF_H) */
/* Turn off input and output for process PROC. */
-void
+static void
deactivate_process (Lisp_Object proc)
{
register int inchannel, outchannel;
if (FD_ISSET (inchannel, &connect_wait_mask))
{
FD_CLR (inchannel, &connect_wait_mask);
+ FD_CLR (inchannel, &write_mask);
if (--num_pending_connects < 0)
abort ();
}
struct sockaddr_un un;
#endif
} saddr;
- int len = sizeof saddr;
+ socklen_t len = sizeof saddr;
s = accept (channel, &saddr.sa, &len);
p->encode_coding_system = ps->encode_coding_system;
setup_process_coding_systems (proc);
- p->decoding_buf = make_uninit_string (0);
+ p->decoding_buf = empty_unibyte_string;
p->decoding_carryover = 0;
- p->encoding_buf = make_uninit_string (0);
+ p->encoding_buf = empty_unibyte_string;
p->inherit_coding_system_flag
= (NILP (buffer) ? 0 : ps->inherit_coding_system_flag);
{
register int channel, nfds;
SELECT_TYPE Available;
-#ifdef NON_BLOCKING_CONNECT
- SELECT_TYPE Connecting;
- int check_connect;
-#endif
+ SELECT_TYPE Writeok;
+ int check_write;
int check_delay, no_avail;
int xerrno;
Lisp_Object proc;
int count = SPECPDL_INDEX ();
FD_ZERO (&Available);
-#ifdef NON_BLOCKING_CONNECT
- FD_ZERO (&Connecting);
-#endif
+ FD_ZERO (&Writeok);
- if (time_limit == 0 && wait_proc && !NILP (Vinhibit_quit)
+ if (time_limit == 0 && microsecs == 0 && wait_proc && !NILP (Vinhibit_quit)
&& !(CONSP (wait_proc->status) && EQ (XCAR (wait_proc->status), Qexit)))
message ("Blocking call to accept-process-output with quit inhibited!!");
struct buffer *old_buffer = current_buffer;
Lisp_Object old_window = selected_window;
- timer_delay = timer_check (1);
+ timer_delay = timer_check ();
/* If a timer has run, this might have changed buffers
an alike. Make read_key_sequence aware of that. */
if (update_tick != process_tick)
{
SELECT_TYPE Atemp;
-#ifdef NON_BLOCKING_CONNECT
SELECT_TYPE Ctemp;
-#endif
if (kbd_on_hold_p ())
FD_ZERO (&Atemp);
else
Atemp = input_wait_mask;
- IF_NON_BLOCKING_CONNECT (Ctemp = connect_wait_mask);
+ Ctemp = write_mask;
EMACS_SET_SECS_USECS (timeout, 0, 0);
- if ((select (max (max (max_process_desc, max_keyboard_desc),
- max_gpm_desc) + 1,
+ if ((select (max (max_process_desc, max_input_desc) + 1,
&Atemp,
#ifdef NON_BLOCKING_CONNECT
(num_pending_connects > 0 ? &Ctemp : (SELECT_TYPE *)0),
break;
FD_SET (wait_proc->infd, &Available);
check_delay = 0;
- IF_NON_BLOCKING_CONNECT (check_connect = 0);
+ check_write = 0;
}
else if (!NILP (wait_for_cell))
{
Available = non_process_wait_mask;
check_delay = 0;
- IF_NON_BLOCKING_CONNECT (check_connect = 0);
+ check_write = 0;
}
else
{
Available = non_keyboard_wait_mask;
else
Available = input_wait_mask;
- IF_NON_BLOCKING_CONNECT (check_connect = (num_pending_connects > 0));
+ Writeok = write_mask;
+#ifdef SELECT_CANT_DO_WRITE_MASK
+ check_write = 0;
+#else
+ check_write = 1;
+#endif
check_delay = wait_channel >= 0 ? 0 : process_output_delay_count;
}
}
else
{
-#ifdef NON_BLOCKING_CONNECT
- if (check_connect)
- Connecting = connect_wait_mask;
-#endif
#ifdef ADAPTIVE_READ_BUFFERING
/* Set the timeout for adaptive read buffering if any
#else
nfds = select
#endif
- (max (max (max_process_desc, max_keyboard_desc),
- max_gpm_desc) + 1,
- &Available,
-#ifdef NON_BLOCKING_CONNECT
- (check_connect ? &Connecting : (SELECT_TYPE *)0),
-#else
- (SELECT_TYPE *)0,
-#endif
- (SELECT_TYPE *)0, &timeout);
+ (max (max_process_desc, max_input_desc) + 1,
+ &Available,
+ (check_write ? &Writeok : (SELECT_TYPE *)0),
+ (SELECT_TYPE *)0, &timeout);
}
xerrno = errno;
if (no_avail)
{
FD_ZERO (&Available);
- IF_NON_BLOCKING_CONNECT (check_connect = 0);
+ check_write = 0;
}
#if 0 /* When polling is used, interrupt_input is 0,
if (no_avail || nfds == 0)
continue;
- /* Really FIRST_PROC_DESC should be 0 on Unix,
- but this is safer in the short run. */
+ for (channel = 0; channel <= max_input_desc; ++channel)
+ {
+ struct fd_callback_data *d = &fd_callback_info[channel];
+ if (FD_ISSET (channel, &Available)
+ && d->func != 0
+ && (d->condition & FOR_READ) != 0)
+ d->func (channel, d->data, 1);
+ if (FD_ISSET (channel, &write_mask)
+ && d->func != 0
+ && (d->condition & FOR_WRITE) != 0)
+ d->func (channel, d->data, 0);
+ }
+
for (channel = 0; channel <= max_process_desc; channel++)
{
if (FD_ISSET (channel, &Available)
- && FD_ISSET (channel, &non_keyboard_wait_mask))
+ && FD_ISSET (channel, &non_keyboard_wait_mask)
+ && !FD_ISSET (channel, &non_process_wait_mask))
{
int nread;
}
}
#ifdef NON_BLOCKING_CONNECT
- if (check_connect && FD_ISSET (channel, &Connecting)
+ if (FD_ISSET (channel, &Writeok)
&& FD_ISSET (channel, &connect_wait_mask))
{
struct Lisp_Process *p;
FD_CLR (channel, &connect_wait_mask);
+ FD_CLR (channel, &write_mask);
if (--num_pending_connects < 0)
abort ();
/* getsockopt(,,SO_ERROR,,) is said to hang on some systems.
So only use it on systems where it is known to work. */
{
- int xlen = sizeof (xerrno);
+ socklen_t xlen = sizeof (xerrno);
if (getsockopt (channel, SOL_SOCKET, SO_ERROR, &xerrno, &xlen))
xerrno = errno;
}
}
static Lisp_Object
-read_process_output_error_handler (Lisp_Object error)
+read_process_output_error_handler (Lisp_Object error_val)
{
- cmd_error_internal (error, "error in process filter: ");
+ cmd_error_internal (error_val, "error in process filter: ");
Vinhibit_quit = Qt;
update_echo_area ();
Fsleep_for (make_number (2), Qnil);
static int
read_process_output (Lisp_Object proc, register int channel)
{
- register int nbytes;
+ register ssize_t nbytes;
char *chars;
register Lisp_Object outstream;
register struct Lisp_Process *p = XPROCESS (proc);
- register int opoint;
+ register EMACS_INT opoint;
struct coding_system *coding = proc_decode_coding_system[channel];
int carryover = p->decoding_carryover;
int readmax = 4096;
/* We have a working select, so proc_buffered_char is always -1. */
if (DATAGRAM_CHAN_P (channel))
{
- int len = datagram_address[channel].len;
+ socklen_t len = datagram_address[channel].len;
nbytes = recvfrom (channel, chars + carryover, readmax,
0, datagram_address[channel].sa, &len);
}
else
#endif
- if (proc_buffered_char[channel] < 0)
{
- nbytes = emacs_read (channel, chars + carryover, readmax);
+ int buffered = 0 <= proc_buffered_char[channel];
+ if (buffered)
+ {
+ chars[carryover] = proc_buffered_char[channel];
+ proc_buffered_char[channel] = -1;
+ }
+#ifdef HAVE_GNUTLS
+ if (XPROCESS (proc)->gnutls_p)
+ nbytes = emacs_gnutls_read (channel, XPROCESS (proc),
+ chars + carryover + buffered,
+ readmax - buffered);
+ else
+#endif
+ nbytes = emacs_read (channel, chars + carryover + buffered,
+ readmax - buffered);
#ifdef ADAPTIVE_READ_BUFFERING
if (nbytes > 0 && p->adaptive_read_buffering)
{
delay += READ_OUTPUT_DELAY_INCREMENT * 2;
}
}
- else if (delay > 0 && (nbytes == readmax))
+ else if (delay > 0 && nbytes == readmax - buffered)
{
delay -= READ_OUTPUT_DELAY_INCREMENT;
if (delay == 0)
}
}
#endif
- }
- else
- {
- chars[carryover] = proc_buffered_char[channel];
- proc_buffered_char[channel] = -1;
- nbytes = emacs_read (channel, chars + carryover + 1, readmax - 1);
- if (nbytes < 0)
- nbytes = 1;
- else
- nbytes = nbytes + 1;
+ nbytes += buffered;
+ nbytes += buffered && nbytes <= 0;
}
p->decoding_carryover = 0;
outstream = p->filter;
if (!NILP (outstream))
{
- Lisp_Object obuffer, okeymap;
Lisp_Object text;
int outer_running_asynch_code = running_asynch_code;
int waiting = waiting_for_user_input_p;
/* No need to gcpro these, because all we do with them later
is test them for EQness, and none of them should be a string. */
+#if 0
+ Lisp_Object obuffer, okeymap;
XSETBUFFER (obuffer, current_buffer);
- okeymap = current_buffer->keymap;
+ okeymap = BVAR (current_buffer, keymap);
+#endif
/* We inhibit quit here instead of just catching it so that
hitting ^G when a filter happens to be running won't screw
save the match data in a special nonrecursive fashion. */
running_asynch_code = 1;
- decode_coding_c_string (coding, chars, nbytes, Qt);
+ decode_coding_c_string (coding, (unsigned char *) chars, nbytes, Qt);
text = coding->dst_object;
Vlast_coding_system_used = CODING_ID_NAME (coding->id);
/* A new coding system might be found. */
}
/* If no filter, write into buffer if it isn't dead. */
- else if (!NILP (p->buffer) && !NILP (XBUFFER (p->buffer)->name))
+ else if (!NILP (p->buffer) && !NILP (BVAR (XBUFFER (p->buffer), name)))
{
Lisp_Object old_read_only;
- int old_begv, old_zv;
- int old_begv_byte, old_zv_byte;
- int before, before_byte;
- int opoint_byte;
+ EMACS_INT old_begv, old_zv;
+ EMACS_INT old_begv_byte, old_zv_byte;
+ EMACS_INT before, before_byte;
+ EMACS_INT opoint_byte;
Lisp_Object text;
struct buffer *b;
Fset_buffer (p->buffer);
opoint = PT;
opoint_byte = PT_BYTE;
- old_read_only = current_buffer->read_only;
+ old_read_only = BVAR (current_buffer, read_only);
old_begv = BEGV;
old_zv = ZV;
old_begv_byte = BEGV_BYTE;
old_zv_byte = ZV_BYTE;
- current_buffer->read_only = Qnil;
+ BVAR (current_buffer, read_only) = Qnil;
/* Insert new output into buffer
at the current end-of-output marker,
if (! (BEGV <= PT && PT <= ZV))
Fwiden ();
- decode_coding_c_string (coding, chars, nbytes, Qt);
+ decode_coding_c_string (coding, (unsigned char *) chars, nbytes, Qt);
text = coding->dst_object;
Vlast_coding_system_used = CODING_ID_NAME (coding->id);
/* A new coding system might be found. See the comment in the
p->decoding_carryover = coding->carryover_bytes;
}
/* Adjust the multibyteness of TEXT to that of the buffer. */
- if (NILP (current_buffer->enable_multibyte_characters)
+ if (NILP (BVAR (current_buffer, enable_multibyte_characters))
!= ! STRING_MULTIBYTE (text))
text = (STRING_MULTIBYTE (text)
? Fstring_as_unibyte (text)
Fnarrow_to_region (make_number (old_begv), make_number (old_zv));
- current_buffer->read_only = old_read_only;
+ BVAR (current_buffer, read_only) = old_read_only;
SET_PT_BOTH (opoint, opoint_byte);
}
/* Handling the process output should not deactivate the mark. */
\f
/* Sending data to subprocess */
-jmp_buf send_process_frame;
-Lisp_Object process_sent_to;
+static jmp_buf send_process_frame;
+static Lisp_Object process_sent_to;
-SIGTYPE
+static void
send_process_trap (int ignore)
{
SIGNAL_THREAD_CHECK (SIGPIPE);
This function can evaluate Lisp code and can garbage collect. */
static void
-send_process (volatile Lisp_Object proc, const unsigned char *volatile buf,
- volatile int len, volatile Lisp_Object object)
+send_process (volatile Lisp_Object proc, const char *volatile buf,
+ volatile EMACS_INT len, volatile Lisp_Object object)
{
/* Use volatile to protect variables from being clobbered by longjmp. */
struct Lisp_Process *p = XPROCESS (proc);
- int rv;
+ ssize_t rv;
struct coding_system *coding;
struct gcpro gcpro1;
- SIGTYPE (*volatile old_sigpipe) (int);
+ void (*volatile old_sigpipe) (int);
GCPRO1 (object);
if ((STRINGP (object) && STRING_MULTIBYTE (object))
|| (BUFFERP (object)
- && !NILP (XBUFFER (object)->enable_multibyte_characters))
+ && !NILP (BVAR (XBUFFER (object), enable_multibyte_characters)))
|| EQ (object, Qt))
{
+ p->encode_coding_system
+ = complement_process_encoding_system (p->encode_coding_system);
if (!EQ (Vlast_coding_system_used, p->encode_coding_system))
- /* The coding system for encoding was changed to raw-text
- because we sent a unibyte text previously. Now we are
- sending a multibyte text, thus we must encode it by the
- original coding system specified for the current process. */
- setup_coding_system (p->encode_coding_system, coding);
+ {
+ /* The coding system for encoding was changed to raw-text
+ because we sent a unibyte text previously. Now we are
+ sending a multibyte text, thus we must encode it by the
+ original coding system specified for the current process.
+
+ Another reason we comming here is that the coding system
+ was just complemented and new one was returned by
+ complement_process_encoding_system. */
+ setup_coding_system (p->encode_coding_system, coding);
+ Vlast_coding_system_used = p->encode_coding_system;
+ }
coding->src_multibyte = 1;
}
else
coding->dst_object = Qt;
if (BUFFERP (object))
{
- int from_byte, from, to;
- int save_pt, save_pt_byte;
+ EMACS_INT from_byte, from, to;
+ EMACS_INT save_pt, save_pt_byte;
struct buffer *cur = current_buffer;
set_buffer_internal (XBUFFER (object));
save_pt = PT, save_pt_byte = PT_BYTE;
- from_byte = PTR_BYTE_POS (buf);
+ from_byte = PTR_BYTE_POS ((unsigned char *) buf);
from = BYTE_TO_CHAR (from_byte);
to = BYTE_TO_CHAR (from_byte + len);
TEMP_SET_PT_BOTH (from, from_byte);
len = coding->produced;
object = coding->dst_object;
- buf = SDATA (object);
+ buf = SSDATA (object);
}
if (pty_max_bytes == 0)
process_sent_to = proc;
while (len > 0)
{
- int this = len;
+ EMACS_INT this = len;
/* Send this batch, using one or more write calls. */
while (this > 0)
{
int outfd = p->outfd;
- old_sigpipe = (SIGTYPE (*) (int)) signal (SIGPIPE, send_process_trap);
+ old_sigpipe = (void (*) (int)) signal (SIGPIPE, send_process_trap);
#ifdef DATAGRAM_SOCKETS
if (DATAGRAM_CHAN_P (outfd))
{
- rv = sendto (outfd, (char *) buf, this,
+ rv = sendto (outfd, buf, this,
0, datagram_address[outfd].sa,
datagram_address[outfd].len);
if (rv < 0 && errno == EMSGSIZE)
else
#endif
{
- rv = emacs_write (outfd, (char *) buf, this);
+#ifdef HAVE_GNUTLS
+ if (XPROCESS (proc)->gnutls_p)
+ rv = emacs_gnutls_write (outfd,
+ XPROCESS (proc),
+ buf, this);
+ else
+#endif
+ rv = emacs_write (outfd, buf, this);
#ifdef ADAPTIVE_READ_BUFFERING
if (p->read_output_delay > 0
&& p->adaptive_read_buffering == 1)
/* Running filters might relocate buffers or strings.
Arrange to relocate BUF. */
if (BUFFERP (object))
- offset = BUF_PTR_BYTE_POS (XBUFFER (object), buf);
+ offset = BUF_PTR_BYTE_POS (XBUFFER (object),
+ (unsigned char *) buf);
else if (STRINGP (object))
- offset = buf - SDATA (object);
+ offset = buf - SSDATA (object);
#ifdef EMACS_HAS_USECS
wait_reading_process_output (0, 20000, 0, 0, Qnil, NULL, 0);
#endif
if (BUFFERP (object))
- buf = BUF_BYTE_ADDRESS (XBUFFER (object), offset);
+ buf = (char *) BUF_BYTE_ADDRESS (XBUFFER (object),
+ offset);
else if (STRINGP (object))
- buf = offset + SDATA (object);
+ buf = offset + SSDATA (object);
rv = 0;
}
(Lisp_Object process, Lisp_Object start, Lisp_Object end)
{
Lisp_Object proc;
- int start1, end1;
+ EMACS_INT start1, end1;
proc = get_process (process);
validate_region (&start, &end);
start1 = CHAR_TO_BYTE (XINT (start));
end1 = CHAR_TO_BYTE (XINT (end));
- send_process (proc, BYTE_POS_ADDR (start1), end1 - start1,
+ send_process (proc, (char *) BYTE_POS_ADDR (start1), end1 - start1,
Fcurrent_buffer ());
return Qnil;
Lisp_Object proc;
CHECK_STRING (string);
proc = get_process (process);
- send_process (proc, SDATA (string),
+ send_process (proc, SSDATA (string),
SBYTES (string), string);
return Qnil;
}
int fd;
/* Some OS:es (Solaris 8/9) does not allow TIOCGPGRP from the
master side. Try the slave side. */
- fd = emacs_open (SDATA (p->tty_name), O_RDONLY, 0);
+ fd = emacs_open (SSDATA (p->tty_name), O_RDONLY, 0);
if (fd != -1)
{
/* If possible, send signals to the entire pgrp
by sending an input character to it. */
- /* TERMIOS is the latest and bestest, and seems most likely to
- work. If the system has it, use it. */
-#ifdef HAVE_TERMIOS
struct termios t;
cc_t *sig_char = NULL;
if (sig_char && *sig_char != CDISABLE)
{
- send_process (proc, sig_char, 1, Qnil);
+ send_process (proc, (char *) sig_char, 1, Qnil);
return;
}
/* If we can't send the signal with a character,
fall through and send it another way. */
-#else /* ! HAVE_TERMIOS */
-
- /* On Berkeley descendants, the following IOCTL's retrieve the
- current control characters. */
-#if defined (TIOCGLTC) && defined (TIOCGETC)
-
- struct tchars c;
- struct ltchars lc;
-
- switch (signo)
- {
- case SIGINT:
- ioctl (p->infd, TIOCGETC, &c);
- send_process (proc, &c.t_intrc, 1, Qnil);
- return;
- case SIGQUIT:
- ioctl (p->infd, TIOCGETC, &c);
- send_process (proc, &c.t_quitc, 1, Qnil);
- return;
-#ifdef SIGTSTP
- case SIGTSTP:
- ioctl (p->infd, TIOCGLTC, &lc);
- send_process (proc, &lc.t_suspc, 1, Qnil);
- return;
-#endif /* ! defined (SIGTSTP) */
- }
-
-#else /* ! defined (TIOCGLTC) && defined (TIOCGETC) */
-
- /* On SYSV descendants, the TCGETA ioctl retrieves the current control
- characters. */
-#ifdef TCGETA
- struct termio t;
- switch (signo)
- {
- case SIGINT:
- ioctl (p->infd, TCGETA, &t);
- send_process (proc, &t.c_cc[VINTR], 1, Qnil);
- return;
- case SIGQUIT:
- ioctl (p->infd, TCGETA, &t);
- send_process (proc, &t.c_cc[VQUIT], 1, Qnil);
- return;
-#ifdef SIGTSTP
- case SIGTSTP:
- ioctl (p->infd, TCGETA, &t);
- send_process (proc, &t.c_cc[VSWTCH], 1, Qnil);
- return;
-#endif /* ! defined (SIGTSTP) */
- }
-#else /* ! defined (TCGETA) */
- Your configuration files are messed up.
- /* If your system configuration files define SIGNALS_VIA_CHARACTERS,
- you'd better be using one of the alternatives above! */
-#endif /* ! defined (TCGETA) */
-#endif /* ! defined (TIOCGLTC) && defined (TIOCGETC) */
- /* In this case, the code above should alway return. */
- abort ();
-#endif /* ! defined HAVE_TERMIOS */
/* The code above may fall through if it can't
handle the signal. */
#ifdef WINDOWSNT
if (fd_info[ p->infd ].flags & FILE_SERIAL)
PurgeComm (fd_info[ p->infd ].hnd, PURGE_RXABORT | PURGE_RXCLEAR);
-#endif
-#ifdef HAVE_TERMIOS
+#else /* not WINDOWSNT */
tcflush (p->infd, TCIFLUSH);
-#endif
+#endif /* not WINDOWSNT */
}
p->command = Qnil;
return process;
;
else
{
- unsigned char *name;
+ char *name;
CHECK_SYMBOL (sigcode);
- name = SDATA (SYMBOL_NAME (sigcode));
+ name = SSDATA (SYMBOL_NAME (sigcode));
if (!strncmp (name, "SIG", 3) || !strncmp (name, "sig", 3))
name += 3;
send_process (proc, "\004", 1, Qnil);
else if (EQ (XPROCESS (proc)->type, Qserial))
{
-#ifdef HAVE_TERMIOS
+#ifndef WINDOWSNT
if (tcdrain (XPROCESS (proc)->outfd) != 0)
error ("tcdrain() failed: %s", emacs_strerror (errno));
-#endif
+#endif /* not WINDOWSNT */
/* Do nothing on Windows because writes are blocking. */
}
else
indirectly; if it does, that is a bug */
#ifdef SIGCHLD
-SIGTYPE
+static void
sigchld_handler (int signo)
{
int old_errno = errno;
}
static Lisp_Object
-exec_sentinel_error_handler (Lisp_Object error)
+exec_sentinel_error_handler (Lisp_Object error_val)
{
- cmd_error_internal (error, "error in process sentinel: ");
+ cmd_error_internal (error_val, "error in process sentinel: ");
Vinhibit_quit = Qt;
update_echo_area ();
Fsleep_for (make_number (2), Qnil);
static void
exec_sentinel (Lisp_Object proc, Lisp_Object reason)
{
- Lisp_Object sentinel, obuffer, odeactivate, okeymap;
+ Lisp_Object sentinel, odeactivate;
register struct Lisp_Process *p = XPROCESS (proc);
int count = SPECPDL_INDEX ();
int outer_running_asynch_code = running_asynch_code;
/* No need to gcpro these, because all we do with them later
is test them for EQness, and none of them should be a string. */
odeactivate = Vdeactivate_mark;
+#if 0
+ Lisp_Object obuffer, okeymap;
XSETBUFFER (obuffer, current_buffer);
- okeymap = current_buffer->keymap;
+ okeymap = BVAR (current_buffer, keymap);
+#endif
/* There's no good reason to let sentinels change the current
buffer, and many callers of accept-process-output, sit-for, and
{
Lisp_Object tem;
struct buffer *old = current_buffer;
- int opoint, opoint_byte;
- int before, before_byte;
+ EMACS_INT opoint, opoint_byte;
+ EMACS_INT before, before_byte;
/* Avoid error if buffer is deleted
(probably that's why the process is dead, too) */
- if (NILP (XBUFFER (buffer)->name))
+ if (NILP (BVAR (XBUFFER (buffer), name)))
continue;
Fset_buffer (buffer);
before = PT;
before_byte = PT_BYTE;
- tem = current_buffer->read_only;
- current_buffer->read_only = Qnil;
+ tem = BVAR (current_buffer, read_only);
+ BVAR (current_buffer, read_only) = Qnil;
insert_string ("\nProcess ");
Finsert (1, &p->name);
insert_string (" ");
Finsert (1, &msg);
- current_buffer->read_only = tem;
+ BVAR (current_buffer, read_only) = tem;
set_marker_both (p->mark, p->buffer, PT, PT_BYTE);
if (opoint >= before)
\f
-static int add_gpm_wait_descriptor_called_flag;
-
void
add_gpm_wait_descriptor (int desc)
{
- if (! add_gpm_wait_descriptor_called_flag)
- FD_CLR (0, &input_wait_mask);
- add_gpm_wait_descriptor_called_flag = 1;
- FD_SET (desc, &input_wait_mask);
- FD_SET (desc, &gpm_wait_mask);
- if (desc > max_gpm_desc)
- max_gpm_desc = desc;
+ add_keyboard_wait_descriptor (desc);
}
void
delete_gpm_wait_descriptor (int desc)
{
- int fd;
- int lim = max_gpm_desc;
-
- FD_CLR (desc, &input_wait_mask);
- FD_CLR (desc, &non_process_wait_mask);
-
- if (desc == max_gpm_desc)
- for (fd = 0; fd < lim; fd++)
- if (FD_ISSET (fd, &input_wait_mask)
- && !FD_ISSET (fd, &non_keyboard_wait_mask)
- && !FD_ISSET (fd, &non_process_wait_mask))
- max_gpm_desc = fd;
+ delete_keyboard_wait_descriptor (desc);
}
/* Return nonzero if *MASK has a bit set
{
int fd;
- for (fd = 0; fd <= max_keyboard_desc; fd++)
+ for (fd = 0; fd <= max_input_desc; fd++)
if (FD_ISSET (fd, mask) && FD_ISSET (fd, &input_wait_mask)
&& !FD_ISSET (fd, &non_keyboard_wait_mask))
return 1;
do
{
int old_timers_run = timers_run;
- timer_delay = timer_check (1);
+ timer_delay = timer_check ();
if (timers_run != old_timers_run && do_display)
/* We must retry, since a timer may have requeued itself
and that could alter the time delay. */
void
add_keyboard_wait_descriptor (int desc)
{
-#ifdef subprocesses
+#ifdef subprocesses /* actually means "not MSDOS" */
FD_SET (desc, &input_wait_mask);
FD_SET (desc, &non_process_wait_mask);
- if (desc > max_keyboard_desc)
- max_keyboard_desc = desc;
+ if (desc > max_input_desc)
+ max_input_desc = desc;
#endif
}
{
#ifdef subprocesses
int fd;
- int lim = max_keyboard_desc;
+ int lim = max_input_desc;
FD_CLR (desc, &input_wait_mask);
FD_CLR (desc, &non_process_wait_mask);
- if (desc == max_keyboard_desc)
+ if (desc == max_input_desc)
for (fd = 0; fd < lim; fd++)
- if (FD_ISSET (fd, &input_wait_mask)
- && !FD_ISSET (fd, &non_keyboard_wait_mask)
- && !FD_ISSET (fd, &gpm_wait_mask))
- max_keyboard_desc = fd;
-#endif /* subprocesses */
+ if (FD_ISSET (fd, &input_wait_mask) || FD_ISSET (fd, &write_mask))
+ max_input_desc = fd;
+#endif
}
/* Setup coding systems of PROCESS. */
;
else if (BUFFERP (p->buffer))
{
- if (NILP (XBUFFER (p->buffer)->enable_multibyte_characters))
+ if (NILP (BVAR (XBUFFER (p->buffer), enable_multibyte_characters)))
coding_system = raw_text_coding_system (coding_system);
}
setup_coding_system (coding_system, proc_decode_coding_system[inch]);
#endif /* subprocesses */
}
-DEFUN ("waiting-for-user-input-p", Fwaiting_for_user_input_p, Swaiting_for_user_input_p,
- 0, 0, 0,
+DEFUN ("waiting-for-user-input-p", Fwaiting_for_user_input_p,
+ Swaiting_for_user_input_p, 0, 0, 0,
doc: /* Returns non-nil if Emacs is waiting for input from the user.
This is intended for use by asynchronous process output filters and sentinels. */)
(void)
FD_ZERO (&input_wait_mask);
FD_ZERO (&non_keyboard_wait_mask);
FD_ZERO (&non_process_wait_mask);
+ FD_ZERO (&write_mask);
max_process_desc = 0;
+ memset (fd_callback_info, 0, sizeof (fd_callback_info));
#ifdef NON_BLOCKING_CONNECT
FD_ZERO (&connect_wait_mask);
processes. As such, we only change the default value. */
if (initialized)
{
- const char *release = get_operating_system_release ();
+ char const *release = (STRINGP (Voperating_system_release)
+ ? SSDATA (Voperating_system_release)
+ : 0);
if (!release || !release[0] || (release[0] < MIN_PTY_KERNEL_VERSION
&& release[1] == '.')) {
Vprocess_connection_type = Qnil;
Qargs = intern_c_string ("args");
staticpro (&Qargs);
- DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
+ DEFVAR_BOOL ("delete-exited-processes", delete_exited_processes,
doc: /* *Non-nil means delete processes immediately when they exit.
A value of nil means don't delete them until `list-processes' is run. */);
delete_exited_processes = 1;
#ifdef subprocesses
- DEFVAR_LISP ("process-connection-type", &Vprocess_connection_type,
+ DEFVAR_LISP ("process-connection-type", Vprocess_connection_type,
doc: /* Control type of device used to communicate with subprocesses.
Values are nil to use a pipe, or t or `pty' to use a pty.
The value has no effect if the system has no ptys or if all ptys are busy:
Vprocess_connection_type = Qt;
#ifdef ADAPTIVE_READ_BUFFERING
- DEFVAR_LISP ("process-adaptive-read-buffering", &Vprocess_adaptive_read_buffering,
+ DEFVAR_LISP ("process-adaptive-read-buffering", Vprocess_adaptive_read_buffering,
doc: /* If non-nil, improve receive buffering by delaying after short reads.
On some systems, when Emacs reads the output from a subprocess, the output data
is read in very small blocks, potentially resulting in very poor performance.
defsubr (&Sprocess_contact);
defsubr (&Sprocess_plist);
defsubr (&Sset_process_plist);
- defsubr (&Slist_processes);
defsubr (&Sprocess_list);
defsubr (&Sstart_process);
-#ifdef HAVE_SERIAL
defsubr (&Sserial_process_configure);
defsubr (&Smake_serial_process);
-#endif /* HAVE_SERIAL */
defsubr (&Sset_network_process_option);
defsubr (&Smake_network_process);
defsubr (&Sformat_network_address);
-#if defined(HAVE_NET_IF_H) && defined(HAVE_SYS_IOCTL_H)
+#if defined(HAVE_NET_IF_H)
#ifdef SIOCGIFCONF
defsubr (&Snetwork_interface_list);
#endif
#if defined(SIOCGIFADDR) || defined(SIOCGIFHWADDR) || defined(SIOCGIFFLAGS)
defsubr (&Snetwork_interface_info);
#endif
-#endif /* defined(HAVE_NET_IF_H) && defined(HAVE_SYS_IOCTL_H) */
+#endif /* defined(HAVE_NET_IF_H) */
#ifdef DATAGRAM_SOCKETS
defsubr (&Sprocess_datagram_address);
defsubr (&Sset_process_datagram_address);
defsubr (&Slist_system_processes);
defsubr (&Sprocess_attributes);
}
-
-/* arch-tag: 3706c011-7b9a-4117-bd4f-59e7f701a4c4
- (do not change this comment) */