zsh-workers
 help / color / mirror / code / Atom feed
* PATCH: zsh/system library
@ 2003-08-30 18:03 Peter Stephenson
  2003-09-02  0:52 ` Vin Shelton
  0 siblings, 1 reply; 6+ messages in thread
From: Peter Stephenson @ 2003-08-30 18:03 UTC (permalink / raw)
  To: Zsh hackers list

Clearing out some patches which have advanced as far as they're likely
to for the time being.

Here is a provisional interface to the read and write system calls via
sysread and syswrite builtins in a new library zsh/system.

An interface to system errors is also provided.  The $errnos array
contains error macro names (EINTR, etc.) and is as I originally proposed
for zsh/params but by popular vote (1 to 0) it has been moved here.
There is also an interface to output (or write to an array) the full
error message.  This is the command syserror; there are several reasons
this is a command rather than another array (1) the messages are much
longer than the names and so waste space in the shell (2) they can
change dynamically due to internationalization support (3) the standard
C interface is a function (4) unlike the ENAMES, you are unlikely to
need them internally in the code.

The other change is that the existing ERRNO parameter is now writable.
This allows setting it to 0 consistent with using the system interface
from C.

I sneaked/snuck in some extra .cvsignore lines which I noticed when I
was adding the documentation.

Yet another internal poll/select call.  Sigh.

Possible enhancements include interfaces to fcntl and lseek.

Further comments welcome.

Index: zshconfig.ac
===================================================================
RCS file: /cvsroot/zsh/zsh/zshconfig.ac,v
retrieving revision 1.37
diff -u -r1.37 zshconfig.ac
--- zshconfig.ac	25 Apr 2003 11:18:51 -0000	1.37
+++ zshconfig.ac	30 Aug 2003 17:43:10 -0000
@@ -1117,6 +1117,39 @@
 SIGNAL_H=$zsh_cv_path_signal_h
 AC_SUBST(SIGNAL_H)dnl
 
+dnl Where are error names located?  Needed as input for errnames1.awk
+AC_CACHE_CHECK(where error names are located, zsh_cv_path_errno_h,
+[dnl Look at the output from the preprocessor.
+dnl We should get lines of the form `# 1 "/usr/include/errno.h"'
+dnl The following assumes the real definitions are in a file which
+dnl contains the name `err'; we could relax this if necessary,
+dnl but then you can get a rather long list of files to test.
+dnl The backslash substitution is to persuade cygwin to cough up
+dnl slashes rather than doubled backslashes in the path.
+echo "#include <errno.h>" > nametmp.c
+errfile_list="`$CPP nametmp.c |
+sed -n 's/^#[ 	].*\"\(.*\)\"/\1/p' |
+sed 's/\\\\\\\\/\//g' |
+$AWK '{ if (\$1 ~ \"err\") files[[\$1]] = \$1 }
+  END { for (var in files) print var }'`"
+rm -f nametmp.c
+for ERRNO_H in $errfile_list /dev/null
+do
+  dnl Try to make sure it doesn't get confused by files that don't
+  dnl have real error definitions in.  Count definitions to make sure.
+  nerrs=`test -f $ERRNO_H && \
+  grep '#[ 	]*define[ 	][ 	]*E[0-9A-Z]*[ 	]*[0-9][0-9]*' $ERRNO_H | \
+  wc -l | sed 's/[ 	]//g'`
+  test "x$nerrs" != x && test "$nerrs" -ge 7 && break
+done
+if test $ERRNO_H = "/dev/null"; then
+  AC_MSG_ERROR(ERROR MACROS NOT FOUND:  please report to developers)
+fi
+zsh_cv_path_errno_h=$ERRNO_H
+])
+ERRNO_H=$zsh_cv_path_errno_h
+AC_SUBST(ERRNO_H)dnl
+
 dnl -----------------------------------------------------
 dnl Look for the file containing the RLIMIT_* definitions
 dnl -----------------------------------------------------
Index: Doc/.cvsignore
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/.cvsignore,v
retrieving revision 1.3
diff -u -r1.3 .cvsignore
--- Doc/.cvsignore	5 May 2003 06:14:51 -0000	1.3
+++ Doc/.cvsignore	30 Aug 2003 17:43:12 -0000
@@ -15,3 +15,4 @@
 zsh_*.ps
 infodir
 *.swp
+zsh.pdf zsh_a4.pdf zsh_us.pdf
Index: Doc/Makefile.in
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Makefile.in,v
retrieving revision 1.17
diff -u -r1.17 Makefile.in
--- Doc/Makefile.in	6 Feb 2003 12:21:51 -0000	1.17
+++ Doc/Makefile.in	30 Aug 2003 17:43:13 -0000
@@ -60,10 +60,11 @@
 Zsh/mod_deltochar.yo Zsh/mod_example.yo Zsh/mod_files.yo \
 Zsh/mod_mapfile.yo Zsh/mod_mathfunc.yo Zsh/mod_parameter.yo Zsh/mod_pcre.yo \
 Zsh/mod_sched.yo Zsh/mod_socket.yo \
-Zsh/mod_stat.yo Zsh/mod_termcap.yo Zsh/mod_terminfo.yo \
+Zsh/mod_stat.yo  Zsh/mod_system.yo Zsh/mod_tcp.yo \
+Zsh/mod_termcap.yo Zsh/mod_terminfo.yo \
 Zsh/mod_zftp.yo Zsh/mod_zle.yo Zsh/mod_zleparameter.yo \
 Zsh/mod_zprof.yo Zsh/mod_zpty.yo Zsh/mod_zselect.yo \
-Zsh/mod_zutil.yo Zsh/mod_tcp.yo
+Zsh/mod_zutil.yo
 
 YODLSRC = zmacros.yo zman.yo ztexi.yo Zsh/arith.yo Zsh/builtins.yo \
 Zsh/compat.yo Zsh/compctl.yo Zsh/compsys.yo Zsh/compwid.yo Zsh/cond.yo \
Index: Doc/Zsh/mod_system.yo
===================================================================
RCS file: Doc/Zsh/mod_system.yo
diff -N Doc/Zsh/mod_system.yo
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Doc/Zsh/mod_system.yo	30 Aug 2003 17:43:13 -0000
@@ -0,0 +1,128 @@
+COMMENT(!MOD!zsh/system
+A builtin interface to various low-level system features.
+!MOD!)
+The tt(zsh/system) module makes available three builtin commands and
+a parameter.
+
+sect(Builtins)
+
+startitem()
+findex(syserror)
+item(tt(syserror) tt([ -e) var(errvar) tt(] [ -p) var(prefix) tt(] [) var(errno) tt(|) var(errname ]))(
+This command prints out the error message associated with var(errno), a
+system error number, followed by a newline to standard error.
+
+Instead of the error number, a name var(errname), for example
+tt(ENOENT), may be used.  The set of names is the same as the contents
+of the array tt(errnos), see below.
+
+If the string var(prefix) is given, it is printed in front of the error
+message, with no intervening space.
+
+If var(errvar) is supplied, the entire message, without a newline, is
+assigned to the parameter names var(errvar) and nothing is output.
+
+A return value of 0 indicates the message was successfully printed
+(although it may not be useful if the error number was out of the
+system's range), a return value of 1 indicates an error in the
+parameters, and a return value of 2 indicates the error name was
+not recognised (no message is printed for this).
+)
+findex(sysread)
+xitem(tt(sysread [ -c) var(countvar) tt(] [ -i) var(infd) tt(] [ -o) var(outfd) tt(]))
+item(  tt([ -s) var(bufsize) tt(] [ -t) var(timeout) tt(] [) var(param) tt(]))(
+Perform a single system read from file descriptor var(infd), or zero if
+that is not given.  The result of the read is stored in var(param) or
+var(REPLY) if that is not given.  If var(countvar) is given, the number
+of bytes read is assigned to the parameter named by var(countvar).
+
+The maximum number of bytes read is var(bufsize) or 8192 if that is not
+given, however the command returns as soon as any number of bytes was
+successfully read.
+
+If var(timeout) is given, it specifies a timeout in seconds, which may
+be zero to poll the file descriptor.  This is handled by the tt(poll)
+system call if available, otherwise the tt(select) system call if
+available.
+
+If var(outfd) is given, an attempt is made to write all the bytes just
+read to the file descriptor var(outfd).  If this fails, because of a
+system error other than tt(EINTR) or because of an internal zsh error
+during an interrupt, the bytes read but not written are stored in the
+parameter named by var(param) if supplied (no default is used in this
+case), and the number of bytes read but not written is stored in the
+parameter named by var(countvar) if that is supplied.  If it was
+successful, var(countvar) contains the full number of bytes transferred,
+as usual, and var(param) is not set.
+
+The error tt(EINTR) (interrupted system call) is handled internally so
+that shell interrupts are transparent to the caller.  Any other error
+causes a return.
+
+The possible return values are
+startitem()
+item(0)(
+At least one byte of data was successfully read and, if appropriate,
+written.
+)
+item(1)(
+There was an error in the parameters to the command.  This is the only
+error for which a message is printed to standard error.
+)
+item(2)(
+There was an error on the read, or on polling the input file descriptor
+for a timeout.  The parameter tt(ERRNO) gives the error.
+)
+item(3)(
+Data were successfully read, but there was an error writing them
+to var(outfd).  The parameter tt(ERRNO) gives the error.
+)
+item(4)(
+The attempt to read timed out.  Note this does not set tt(ERRNO) as this
+is not a system error.
+)
+item(5)(
+No system error occurred, but zero bytes were read.  This usually
+indicates end of file.  The parameters are set according to the
+usual rules; no write to var(outfd) is attempted.
+)
+enditem()
+)
+item(tt(syswrite [ -c) var(countvar) tt(] [ -o) var(outfd) tt(]) var(data))(
+The data (a single string of bytes) are written to the file descriptor
+var(outfd), or 1 if that is not given, using the tt(write) system call.
+Multiple write operations may be used if the first does not write all
+the data.
+
+If var(countvar) is given, the number of byte written is stored in the
+parameter named by var(countvar); this may not be the full length of
+var(data) if an error occurred.
+
+The error tt(EINTR) (interrupted system call) is handled internally by
+retrying; otherwise an error causes the command to return.  For example,
+if the file descriptor is set to non-blocking output, an error
+tt(EAGAIN) (on some systems, tt(EWOULDBLOCK)) may result in the command
+returning early.
+
+The return status may be 0 for success, 1 for an error in the parameters
+to the command, or 2 for an error on the write; no error message is
+printed in the last case, but the parameter tt(ERRNO) will reflect
+the error that occurred.
+)
+enditem()
+
+sect(Parameters)
+
+startitem()
+item(tt(errnos))(
+A readonly array of the names of errors defined on the system.  These
+are typically macros defined in C by including the system header file
+tt(errno.h).  The index of each name (assuming the option tt(KSH_ARRAYS)
+is unset) corresponds to the error number.  Error numbers var(num)
+before the last known error which have no name are given the name
+tt(E)var(num) in the array.
+
+Note that aliases for errors are not handled; only the canonical name is
+used.
+)
+enditem()
Index: Doc/Zsh/params.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/params.yo,v
retrieving revision 1.18
diff -u -r1.18 params.yo
--- Doc/Zsh/params.yo	4 Jul 2003 16:05:20 -0000	1.18
+++ Doc/Zsh/params.yo	30 Aug 2003 17:43:19 -0000
@@ -520,7 +520,8 @@
 The value of errno (see manref(errno)(3))
 as set by the most recently failed system call.
 This value is system dependent and is intended for debugging
-purposes.
+purposes.  It is also useful with the tt(zsh/system) module which
+allows the number to be turned into a name or message.
 )
 vindex(GID)
 item(tt(GID) <S>)(
Index: Src/params.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/params.c,v
retrieving revision 1.71
diff -u -r1.71 params.c
--- Src/params.c	4 Apr 2003 16:47:07 -0000	1.71
+++ Src/params.c	30 Aug 2003 17:43:38 -0000
@@ -137,7 +137,7 @@
 #define GFN(X) BR(((char *(*)_((Param)))(X)))
 #define IPDEF1(A,B,C,D) {NULL,A,PM_INTEGER|PM_SPECIAL|D,BR(NULL),SFN(C),GFN(B),stdunsetfn,10,NULL,NULL,NULL,0}
 IPDEF1("#", poundgetfn, nullintsetfn, PM_READONLY),
-IPDEF1("ERRNO", errnogetfn, nullintsetfn, PM_READONLY),
+IPDEF1("ERRNO", errnogetfn, errnosetfn, 0),
 IPDEF1("GID", gidgetfn, gidsetfn, PM_DONTIMPORT | PM_RESTRICTED),
 IPDEF1("EGID", egidgetfn, egidsetfn, PM_DONTIMPORT | PM_RESTRICTED),
 IPDEF1("HISTSIZE", histsizegetfn, histsizesetfn, PM_RESTRICTED),
@@ -3012,6 +3012,15 @@
 {
     if ((savehistsiz = v) < 0)
 	savehistsiz = 0;
+}
+
+/* Function to set value for special parameter `ERRNO' */
+
+/**/
+void
+errnosetfn(Param pm, zlong x)
+{
+    errno = (int)x;
 }
 
 /* Function to get value for special parameter `ERRNO' */
Index: Src/Modules/.cvsignore
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/.cvsignore,v
retrieving revision 1.2
diff -u -r1.2 .cvsignore
--- Src/Modules/.cvsignore	5 May 2003 06:14:51 -0000	1.2
+++ Src/Modules/.cvsignore	30 Aug 2003 17:43:47 -0000
@@ -13,3 +13,4 @@
 *.mdhs
 *.mdh.tmp
 *.swp
+ernames.c errcount.h
Index: Src/Modules/errnames1.awk
===================================================================
RCS file: Src/Modules/errnames1.awk
diff -N Src/Modules/errnames1.awk
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Src/Modules/errnames1.awk	30 Aug 2003 17:43:47 -0000
@@ -0,0 +1,18 @@
+# Edited version of Src/signames1.awk.
+#
+# This is an awk script which finds out what the possibilities for
+# the error names are, and dumps them out so that cpp can turn them
+# into numbers.  Since we don't need to decide here what the
+# real signals are, we can afford to be generous about definitions,
+# in case the definitions are in terms of other definitions.
+# However, we need to avoid definitions with parentheses, which will
+# mess up the syntax.
+BEGIN { printf "#include <errno.h>\n\n" }
+
+/^[\t ]*#[\t ]*define[\t ]*E[A-Z0-9]*[\t ][\t ]*[^(\t ]/ { 
+    eindex = index($0, "E")
+    etail = substr($0, eindex, 80)
+    split(etail, tmp)
+    enam = substr(tmp[1], 2, 20)
+    printf("XXNAMES XXE%s E%s\n", enam, enam)
+}
Index: Src/Modules/errnames2.awk
===================================================================
RCS file: Src/Modules/errnames2.awk
diff -N Src/Modules/errnames2.awk
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Src/Modules/errnames2.awk	30 Aug 2003 17:43:47 -0000
@@ -0,0 +1,42 @@
+# Edited version of Src/signames2.awk.
+#
+# {g,n}awk script to generate errnames.c
+# This version relies on the previous output of the preprocessor
+# on sigtmp.c, sigtmp.out, which is in turn generated by errnames1.awk.
+#
+# NB: On SunOS 4.1.3 - user-functions don\'t work properly, also \" problems
+# Without 0 + hacks some nawks compare numbers as strings
+#
+/^XXNAMES XXE[A-Z0-9]*[\t ][\t ]*[1-9][0-9]*/ {
+    eindex = index($0, "E")
+    etail = substr($0, 11, 80)
+    split(etail, tmp)
+    enam = tmp[1]
+    enum = tmp[2]
+    if (errname[enum] == "") {
+	errname[enum] = enam
+	if (0 + max < 0 + enum && enum < 1024)
+	    max = enum
+    }
+}
+
+END {
+    ps = "%s"
+    printf "/** errnames.c                                 **/\n"
+    printf "/** architecture-customized errnames.c for zsh **/\n"
+    printf "\n"
+    printf "#define ERRCOUNT\t%d\n", max
+    printf "\n"
+    printf "#include %csystem.mdh%c\n", 34, 34
+    printf "\n"
+    printf "/**/\n"
+    printf "const char *sys_errnames[ERRCOUNT+1] = {\n"
+
+    for (i = 1; i <= 0 + max; i++)
+	if (errname[i] == "")
+	    printf("\t%cE%d%c,\n", 34, i, 34)
+	else
+	    printf("\t%c%s%c,\n", 34, errname[i], 34)
+    print "\tNULL"
+    print "};"
+}
Index: Src/Modules/system.c
===================================================================
RCS file: Src/Modules/system.c
diff -N Src/Modules/system.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Src/Modules/system.c	30 Aug 2003 17:43:49 -0000
@@ -0,0 +1,418 @@
+/*
+ * sysread.c - interface to system read/write
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 1998-2003 Peter Stephenson
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Peter Stephenson or the Zsh Development
+ * Group be liable to any party for direct, indirect, special, incidental,
+ * or consequential damages arising out of the use of this software and
+ * its documentation, even if Peter Stephenson, and the Zsh
+ * Development Group have been advised of the possibility of such damage.
+ *
+ * Peter Stephenson and the Zsh Development Group specifically
+ * disclaim any warranties, including, but not limited to, the implied
+ * warranties of merchantability and fitness for a particular purpose.  The
+ * software provided hereunder is on an "as is" basis, and Peter Stephenson
+ * and the Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+
+#include "system.mdh"
+#include "system.pro"
+
+#ifdef HAVE_POLL_H
+# include <poll.h>
+#endif
+#if defined(HAVE_POLL) && !defined(POLLIN)
+# undef HAVE_POLL
+#endif
+
+#define SYSREAD_BUFSIZE	8192
+
+/**/
+static int
+getposint(char *instr, char *nam)
+{
+    char *eptr;
+    int ret;
+
+    ret = (int)zstrtol(instr, &eptr, 10);
+    if (*eptr || ret < 0) {
+	zwarnnam(nam, "integer expected: %s", instr, 0);
+	return -1;
+    }
+
+    return ret;
+}
+
+
+/*
+ * Return values of bin_sysread:
+ *	0	Successfully read (and written if appropriate)
+ *	1	Error in parameters to command
+ *	2	Error on read, or polling read fd ) ERRNO set by
+ *      3	Error on write			  ) system
+ *	4	Timeout on read
+ *	5       Zero bytes read, end of file
+ */
+
+/**/
+static int
+bin_sysread(char *nam, char **args, Options ops, int func)
+{
+    int infd = 0, outfd = -1, bufsize = SYSREAD_BUFSIZE, count;
+    char *outvar = NULL, *countvar = NULL, *inbuf;
+
+    /* -i: input file descriptor if not stdin */
+    if (OPT_ISSET(ops, 'i')) {
+	infd = getposint(OPT_ARG(ops, 'i'), nam);
+	if (infd < 0)
+	    return 1;
+    }
+
+    /* -o: output file descriptor, else store in REPLY */
+    if (OPT_ISSET(ops, 'o')) {
+	if (*args) {
+	    zwarnnam(nam, "no argument allowed with -o", NULL, 0);
+	    return 1;
+	}
+	outfd = getposint(OPT_ARG(ops, 'o'), nam);
+	if (outfd < 0)
+	    return 1;
+    }
+
+    /* -s: buffer size if not default SYSREAD_BUFSIZE */
+    if (OPT_ISSET(ops, 's')) {
+	bufsize = getposint(OPT_ARG(ops, 's'), nam);
+	if (bufsize < 0)
+	    return 1;
+    }
+
+    /* -c: name of variable to store count of transferred bytes */
+    if (OPT_ISSET(ops, 'c')) {
+	countvar = OPT_ARG(ops, 'c');
+	if (!isident(countvar)) {
+	    zwarnnam(nam, "not an identifier: %s", countvar, 0);
+	    return 1;
+	}
+    }
+
+    if (*args) {
+	/*
+	 * Variable in which to store result if doing a plain read.
+	 * Default variable if not specified is REPLY.
+	 * If writing, only stuff we couldn't write is stored here,
+	 * no default in that case (we just discard it if no variable).
+	 */
+	outvar = *args;
+	if (!isident(outvar)) {
+	    zwarnnam(nam, "not an identifier: %s", outvar, 0);
+	    return 1;
+	}
+    }
+
+    inbuf = zhalloc(bufsize);
+
+#if defined(HAVE_POLL) || defined(HAVE_SELECT)
+    /* -t: timeout */
+    if (OPT_ISSET(ops, 't'))
+    {
+# ifdef HAVE_POLL
+	struct pollfd poll_fd;
+	mnumber to_mn;
+	int to_int, ret;
+
+	poll_fd.fd = infd;
+	poll_fd.events = POLLIN;
+
+	to_mn = matheval(OPT_ARG(ops, 't'));
+	if (errflag)
+	    return 1;
+	if (to_mn.type == MN_FLOAT)
+	    to_int = (int) (1000 * to_mn.u.d);
+	else
+	    to_int = 1000 * (int)to_mn.u.l;
+
+	while ((ret = poll(&poll_fd, 1, to_int)) < 0) {
+	    if (errno != EINTR || errflag || retflag || breaks || contflag)
+		break;
+	}
+	if (ret <= 0) {
+	    /* treat non-timeout error as error on read */
+	    return ret ? 2 : 4;
+	}
+# else
+	/* using select */
+	struct timeval select_tv;
+	fd_set fds;
+	mnumber to_mn;
+	int ret;
+
+	FD_ZERO(&fds);
+	FD_SET(infd, &fds);
+	to_mn = matheval(OPT_ARG(ops, 't'));
+	if (errflag)
+	    return 1;
+
+	if (to_mn.type == MN_FLOAT) {
+	    select_tv.tv_sec = (int) to_mn.u.d;
+	    select_tv.tv_usec =
+		(int) ((to_mn.u.d - select_tv.tv_sec) * 1e6);
+	} else {
+	    select_tv.tv_sec = (int) to_mn.u.l;
+	    select_tv.tv_usec = 0;
+	}
+
+	while ((ret = select(infd+1, (SELECT_ARG_2_T) &fds, 
+			     NULL, NULL,&select_tv)) < 1) {
+	    if (errno != EINTR || errflag || retflag || breaks || contflag)
+		break;
+	}
+	if (ret <= 0) {
+	    /* treat non-timeout error as error on read */
+	    return ret ? 2 : 4;
+	}
+# endif
+    }
+#endif
+
+    while ((count = read(infd, inbuf, bufsize)) < 0) {
+	if (errno != EINTR || errflag || retflag || breaks || contflag)
+	    break;
+    }
+    if (countvar)
+	setiparam(countvar, count);
+    if (count < 0)
+	return 2;
+
+    if (outfd >= 0) {
+	if (!count)
+	    return 5;
+	while (count > 0) {
+	    int ret;
+
+	    ret = write(outfd, inbuf, count);
+	    if (ret < 0) {
+		if (errno == EINTR && !errflag &&
+		    !retflag && !breaks && !contflag)
+		    continue;
+		if (outvar)
+		    setsparam(outvar, metafy(inbuf, count, META_DUP));
+		if (countvar)
+		    setiparam(countvar, count);
+		return 3;
+	    }
+	    inbuf += ret;
+	    count -= ret;
+	}
+	return 0;
+    }
+
+    if (!outvar)
+	    outvar = "REPLY";
+    /* do this even if we read zero bytes */
+    setsparam(outvar, metafy(inbuf, count, META_DUP));
+
+    return count ? 0 : 5;
+}
+
+
+/*
+ * Return values of bin_syswrite:
+ *	0	Successfully written
+ *	1	Error in parameters to command
+ *	2	Error on write, ERRNO set by system
+ */
+
+/**/
+static int
+bin_syswrite(char *nam, char **args, Options ops, int func)
+{
+    int outfd = 1, len, count, totcount;
+    char *countvar = NULL;
+
+    /* -o: output file descriptor if not stdout */
+    if (OPT_ISSET(ops, 'o')) {
+	outfd = getposint(OPT_ARG(ops, 'o'), nam);
+	if (outfd < 0)
+	    return 1;
+    }
+
+    /* -c: variable in which to store count of bytes written */
+    if (OPT_ISSET(ops, 'c')) {
+	countvar = OPT_ARG(ops, 'c');
+	if (!isident(countvar)) {
+	    zwarnnam(nam, "not an identifier: %s", countvar, 0);
+	    return 1;
+	}
+    }
+
+    totcount = 0;
+    unmetafy(*args, &len);
+    while (len) {
+	while ((count = write(outfd, *args, len)) < 0) {
+	    if (errno != EINTR || errflag || retflag || breaks || contflag)
+	    {
+		if (countvar)
+		    setiparam(countvar, totcount);
+		return 2;
+	    }
+	}
+	*args += count;
+	totcount += count;
+	len -= count;
+    }
+    if (countvar)
+	setiparam(countvar, totcount);
+
+    return 0;
+}
+
+
+/*
+ * Return values of bin_syserror:
+ *	0	Successfully processed error
+ *		(although if the number was invalid the string
+ *		may not be useful)
+ *	1	Error in parameters
+ *	2	Name of error not recognised.
+ */
+
+/**/
+static int
+bin_syserror(char *nam, char **args, Options ops, int func)
+{
+    int num = 0;
+    char *errvar = NULL, *msg, *pfx = "", *str;
+
+    /* variable in which to write error message */
+    if (OPT_ISSET(ops, 'e')) {
+	errvar = OPT_ARG(ops, 'e');
+	if (!isident(errvar)) {
+	    zwarnnam(nam, "not an identifier: %s", errvar, 0);
+	    return 1;
+	}
+    }
+    /* prefix for error message */
+    if (OPT_ISSET(ops, 'p'))
+	pfx = OPT_ARG(ops, 'p');
+
+    if (!*args)
+	num = errno;
+    else {
+	char *ptr = *args;
+	while (*ptr && idigit(*ptr))
+	    ptr++;
+	if (!*ptr && ptr > *args)
+	    num = atoi(*args);
+	else {
+	    const char **eptr;
+	    for (eptr = sys_errnames; *eptr; eptr++) {
+		if (!strcmp(*eptr, *args)) {
+		    num = (eptr - sys_errnames) + 1;
+		    break;
+		}
+	    }
+	    if (!*eptr)
+		return 2;
+	}
+    }
+
+    msg = strerror(num);
+    if (errvar) {
+	str = (char *)zalloc(strlen(msg) + strlen(pfx) + 1);
+	sprintf(str, "%s%s", pfx, msg);
+	setsparam(errvar, str);
+    } else {
+	fprintf(stderr, "%s%s\n", pfx, msg);
+    }
+
+    return 0;
+}
+
+
+/* Functions for the errnos special parameter. */
+
+/**/
+static char **
+errnosgetfn(Param pm)
+{
+    /* arrdup etc. should really take const pointers as arguments */
+    return arrdup((char **)sys_errnames);
+}
+
+
+static struct builtin bintab[] = {
+    BUILTIN("syserror", 0, bin_syserror, 0, 1, 0, "e:p:", NULL),
+    BUILTIN("sysread", 0, bin_sysread, 0, 1, 0, "c:i:o:s:t:", NULL),
+    BUILTIN("syswrite", 0, bin_syswrite, 1, 1, 0, "c:o:", NULL),
+};
+
+
+/* The load/unload routines required by the zsh library interface */
+
+/**/
+int
+setup_(Module m)
+{
+    return 0;
+}
+
+/**/
+static void
+tidyparam(Param pm)
+{
+    if (!pm)
+	return;
+    pm->flags &= ~PM_READONLY;
+    unsetparam_pm(pm, 0, 1);
+}
+
+
+/**/
+int
+boot_(Module m)
+{
+    Param pm_nos;
+
+    /* this takes care of an autoload on errnos */
+    unsetparam("errnos");
+    if (!(pm_nos = createparam("errnos", PM_ARRAY|PM_SPECIAL|PM_READONLY|
+			       PM_HIDE|PM_HIDEVAL|PM_REMOVABLE)))
+	return 1;
+    pm_nos->gets.afn = errnosgetfn;
+
+    if (!addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab))) {
+	tidyparam(pm_nos);
+	return 1;
+    }
+    return 0;
+}
+
+
+/**/
+int
+cleanup_(Module m)
+{
+    tidyparam((Param)paramtab->getnode(paramtab, "errnos"));
+
+    deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+    return 0;
+}
+
+/**/
+int
+finish_(Module m)
+{
+    return 0;
+}
Index: Src/Modules/system.mdd
===================================================================
RCS file: Src/Modules/system.mdd
diff -N Src/Modules/system.mdd
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Src/Modules/system.mdd	30 Aug 2003 17:43:49 -0000
@@ -0,0 +1,27 @@
+name=zsh/system
+link=dynamic
+load=no
+
+autobins="sysread syswrite syserror"
+
+autoparams="errnos"
+
+objects="system.o errnames.o"
+
+headers="errcount.h"
+
+:<<\Make
+errnames.c: errnames1.awk errnames2.awk $(dir_top)/config.h @ERRNO_H@
+	   if [ x@ERRNO_H@ = x ]; then \
+		touch errtmp.out; \
+	   else \
+		$(AWK) -f $(sdir)/errnames1.awk @ERRNO_H@ >errtmp.c; \
+		$(CPP) errtmp.c >errtmp.out; \
+	   fi
+	   $(AWK) -f $(sdir)/errnames2.awk errtmp.out > $@
+	   rm -f errtmp.c errtmp.out
+
+errcount.h: errnames.c
+	grep 'define.*ERRCOUNT' errnames.c > $@
+Make
+

-- 
Peter Stephenson <pws@pwstephenson.fsnet.co.uk>
Work: pws@csr.com
Web: http://www.pwstephenson.fsnet.co.uk


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: PATCH: zsh/system library
  2003-08-30 18:03 PATCH: zsh/system library Peter Stephenson
@ 2003-09-02  0:52 ` Vin Shelton
  2003-09-02  8:04   ` Zefram
  0 siblings, 1 reply; 6+ messages in thread
From: Vin Shelton @ 2003-09-02  0:52 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

Peter,

Peter Stephenson <pws@pwstephenson.fsnet.co.uk> writes:
> An interface to system errors is also provided.  The $errnos array
> contains error macro names (EINTR, etc.) and is as I originally proposed
> for zsh/params but by popular vote (1 to 0) it has been moved here.
> There is also an interface to output (or write to an array) the full
> error message.  This is the command syserror; there are several reasons
> this is a command rather than another array (1) the messages are much
> longer than the names and so waste space in the shell (2) they can
> change dynamically due to internationalization support (3) the standard
> C interface is a function (4) unlike the ENAMES, you are unlikely to
> need them internally in the code.

> Index: zshconfig.ac
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/zshconfig.ac,v
> retrieving revision 1.37
> diff -u -r1.37 zshconfig.ac
> --- zshconfig.ac	25 Apr 2003 11:18:51 -0000	1.37
> +++ zshconfig.ac	30 Aug 2003 17:43:10 -0000
> @@ -1117,6 +1117,39 @@
>  SIGNAL_H=$zsh_cv_path_signal_h
>  AC_SUBST(SIGNAL_H)dnl
>  
> +dnl Where are error names located?  Needed as input for errnames1.awk
> +AC_CACHE_CHECK(where error names are located, zsh_cv_path_errno_h,
> +[dnl Look at the output from the preprocessor.
> +dnl We should get lines of the form `# 1 "/usr/include/errno.h"'
> +dnl The following assumes the real definitions are in a file which
> +dnl contains the name `err'; we could relax this if necessary,
> +dnl but then you can get a rather long list of files to test.
> +dnl The backslash substitution is to persuade cygwin to cough up
> +dnl slashes rather than doubled backslashes in the path.
> +echo "#include <errno.h>" > nametmp.c
> +errfile_list="`$CPP nametmp.c |
> +sed -n 's/^#[ 	].*\"\(.*\)\"/\1/p' |
> +sed 's/\\\\\\\\/\//g' |
> +$AWK '{ if (\$1 ~ \"err\") files[[\$1]] = \$1 }
> +  END { for (var in files) print var }'`"
> +rm -f nametmp.c
> +for ERRNO_H in $errfile_list /dev/null
> +do
> +  dnl Try to make sure it doesn't get confused by files that don't
> +  dnl have real error definitions in.  Count definitions to make sure.
> +  nerrs=`test -f $ERRNO_H && \
> +  grep '#[ 	]*define[ 	][ 	]*E[0-9A-Z]*[ 	]*[0-9][0-9]*' $ERRNO_H | \
> +  wc -l | sed 's/[ 	]//g'`
> +  test "x$nerrs" != x && test "$nerrs" -ge 7 && break
> +done
> +if test $ERRNO_H = "/dev/null"; then
> +  AC_MSG_ERROR(ERROR MACROS NOT FOUND:  please report to developers)
> +fi
> +zsh_cv_path_errno_h=$ERRNO_H
> +])
> +ERRNO_H=$zsh_cv_path_errno_h
> +AC_SUBST(ERRNO_H)dnl
> +
>  dnl -----------------------------------------------------
>  dnl Look for the file containing the RLIMIT_* definitions
>  dnl -----------------------------------------------------

Unfortunately, your CPP hackery does not work on the output of the
Intel C Compiler.  icc generates output like the following from
nametmp.c:

#line 1 "nametmp.c"
#line 1 "/usr/include/errno.h"
 
#line 1 "/usr/include/features.h"

#line 105 "/usr/include/features.h"

....

It's the rather "line" that gets in the way.  Here's the regexp that
works for both icc and gcc on my Linux system at home.  When I get to
work tomorrow, I will test this against the Solaris C compiler.

--- zshconfig.ac~	2003-09-01 00:03:24.000000000 -0400
+++ zshconfig.ac	2003-09-01 20:43:21.000000000 -0400
@@ -1128,7 +1128,7 @@
 dnl slashes rather than doubled backslashes in the path.
 echo "#include <errno.h>" > nametmp.c
 errfile_list="`$CPP nametmp.c |
-sed -n 's/^#[ 	].*\"\(.*\)\"/\1/p' |
+sed -n 's/^#\(line\)\?[ 	].*\"\(.*\)\"/\2/p' |
 sed 's/\\\\\\\\/\//g' |
 $AWK '{ if (\$1 ~ \"err\") files[[\$1]] = \$1 }
   END { for (var in files) print var }'`"

HTH,
  Vin


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: PATCH: zsh/system library
  2003-09-02  0:52 ` Vin Shelton
@ 2003-09-02  8:04   ` Zefram
  2003-09-02  9:56     ` Peter Stephenson
  0 siblings, 1 reply; 6+ messages in thread
From: Zefram @ 2003-09-02  8:04 UTC (permalink / raw)
  To: Vin Shelton; +Cc: Peter Stephenson, Zsh hackers list

Vin Shelton wrote:
>+sed -n 's/^#\(line\)\?[ 	].*\"\(.*\)\"/\2/p' |

Can we rely on sed understanding \(\)\? metacharacters?  Perhaps better
to split this into two commands.

-zefram


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: PATCH: zsh/system library
  2003-09-02  8:04   ` Zefram
@ 2003-09-02  9:56     ` Peter Stephenson
  2003-09-02 15:18       ` Bart Schaefer
  0 siblings, 1 reply; 6+ messages in thread
From: Peter Stephenson @ 2003-09-02  9:56 UTC (permalink / raw)
  To: Zsh hackers list

Zefram wrote:
> Vin Shelton wrote:
> >+sed -n 's/^#\(line\)\?[ 	].*\"\(.*\)\"/\2/p' |
> 
> Can we rely on sed understanding \(\)\? metacharacters?  Perhaps better
> to split this into two commands.

I think you're right; there's no obvious way of getting this through the
Solaris sed in a single regexp.

sed -n -e 's/^#line[ 	].*\"\(.*\)\"/\2/p' \
       -e 's/^#[ 	].*\"\(.*\)\"/\2/p' |

should work.

I would think you need this for both signals (further up zshconfig.ac)
and errors --- probably it's only finding the signals owing to the
backup list of explicit files.

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR Ltd., Science Park, Milton Road,
Cambridge, CB4 0WH, UK                          Tel: +44 (0)1223 692070


**********************************************************************
The information transmitted is intended only for the person or
entity to which it is addressed and may contain confidential 
and/or privileged material. 
Any review, retransmission, dissemination or other use of, or
taking of any action in reliance upon, this information by 
persons or entities other than the intended recipient is 
prohibited.  
If you received this in error, please contact the sender and 
delete the material from any computer.
**********************************************************************


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: PATCH: zsh/system library
  2003-09-02  9:56     ` Peter Stephenson
@ 2003-09-02 15:18       ` Bart Schaefer
  2003-09-07  4:03         ` Vin Shelton
  0 siblings, 1 reply; 6+ messages in thread
From: Bart Schaefer @ 2003-09-02 15:18 UTC (permalink / raw)
  To: Zsh hackers list

On Sep 2, 10:56am, Peter Stephenson wrote:
} Subject: Re: PATCH: zsh/system library
}
} sed -n -e 's/^#line[ 	].*\"\(.*\)\"/\2/p' \
}        -e 's/^#[ 	].*\"\(.*\)\"/\2/p' |
} 
} should work.

Except that those should be \1 instead of \2 in that formulation.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: PATCH: zsh/system library
  2003-09-02 15:18       ` Bart Schaefer
@ 2003-09-07  4:03         ` Vin Shelton
  0 siblings, 0 replies; 6+ messages in thread
From: Vin Shelton @ 2003-09-07  4:03 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

Bart Schaefer <schaefer@brasslantern.com> writes:

> On Sep 2, 10:56am, Peter Stephenson wrote:
> } Subject: Re: PATCH: zsh/system library
> }
> } sed -n -e 's/^#line[ 	].*\"\(.*\)\"/\2/p' \
> }        -e 's/^#[ 	].*\"\(.*\)\"/\2/p' |
> } 
> } should work.
>
> Except that those should be \1 instead of \2 in that formulation.

Here is the patch:

Index: ChangeLog
===================================================================
RCS file: /cvsroot/zsh/zsh/ChangeLog,v
retrieving revision 1.2089
diff -a -u -u -0 -r1.2089 ChangeLog
--- ChangeLog	3 Sep 2003 14:07:25 -0000	1.2089
+++ ChangeLog	7 Sep 2003 04:03:38 -0000
@@ -0,0 +1,4 @@
+2003-09-06  Vin Shelton  <acs@alumni.princeton.edu>
+
+	* zshconfig.ac: Make sed grok icc's cpp output.
+
Index: zshconfig.ac
===================================================================
RCS file: /cvsroot/zsh/zsh/zshconfig.ac,v
retrieving revision 1.39
diff -a -u -r1.39 zshconfig.ac
--- zshconfig.ac	30 Aug 2003 19:16:22 -0000	1.39
+++ zshconfig.ac	7 Sep 2003 04:03:54 -0000
@@ -1081,7 +1081,8 @@
 dnl slashes rather than doubled backslashes in the path.
 echo "#include <signal.h>" > nametmp.c
 sigfile_list="`$CPP nametmp.c |
-sed -n 's/^#[ 	].*\"\(.*\)\"/\1/p' |
+sed -n -e 's/^#line[ 	].*\"\(.*\)\"/\1/p' \
+       -e 's/^#[ 	].*\"\(.*\)\"/\1/p' |
 sed 's/\\\\\\\\/\//g' |
 $AWK '{ if (\$1 ~ \"sig\") files[[\$1]] = \$1 }
   END { for (var in files) print var }'`"
@@ -1128,7 +1129,8 @@
 dnl slashes rather than doubled backslashes in the path.
 echo "#include <errno.h>" > nametmp.c
 errfile_list="`$CPP nametmp.c |
-sed -n 's/^#[ 	].*\"\(.*\)\"/\1/p' |
+sed -n -e 's/^#line[ 	].*\"\(.*\)\"/\1/p' \
+       -e 's/^#[ 	].*\"\(.*\)\"/\1/p' |
 sed 's/\\\\\\\\/\//g' |
 $AWK '{ if (\$1 ~ \"err\") files[[\$1]] = \$1 }
   END { for (var in files) print var }'`"


HTH,
 Vin


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2003-09-07  4:07 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-08-30 18:03 PATCH: zsh/system library Peter Stephenson
2003-09-02  0:52 ` Vin Shelton
2003-09-02  8:04   ` Zefram
2003-09-02  9:56     ` Peter Stephenson
2003-09-02 15:18       ` Bart Schaefer
2003-09-07  4:03         ` Vin Shelton

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).