summaryrefslogtreecommitdiff
path: root/Src/Modules
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2003-08-30 19:06:06 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2003-08-30 19:06:06 +0000
commitc9c5f9da9366d1587c588507433cec35ef243579 (patch)
tree99d69de0866c36adf40dc516c8ab3ab64ad480ce /Src/Modules
parentc016b2dcdc7faade5b279c279b2d506b9ea22bf7 (diff)
downloadzsh-c9c5f9da9366d1587c588507433cec35ef243579.tar.gz
zsh-c9c5f9da9366d1587c588507433cec35ef243579.zip
18980: new zsh/system module
Diffstat (limited to 'Src/Modules')
-rw-r--r--Src/Modules/.cvsignore1
-rw-r--r--Src/Modules/errnames1.awk18
-rw-r--r--Src/Modules/errnames2.awk42
-rw-r--r--Src/Modules/system.c418
-rw-r--r--Src/Modules/system.mdd27
5 files changed, 506 insertions, 0 deletions
diff --git a/Src/Modules/.cvsignore b/Src/Modules/.cvsignore
index d0ea7d755..acafc7ad3 100644
--- a/Src/Modules/.cvsignore
+++ b/Src/Modules/.cvsignore
@@ -13,3 +13,4 @@ so_locations
*.mdhs
*.mdh.tmp
*.swp
+ernames.c errcount.h
diff --git a/Src/Modules/errnames1.awk b/Src/Modules/errnames1.awk
new file mode 100644
index 000000000..5c41197cb
--- /dev/null
+++ b/Src/Modules/errnames1.awk
@@ -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)
+}
diff --git a/Src/Modules/errnames2.awk b/Src/Modules/errnames2.awk
new file mode 100644
index 000000000..60969b423
--- /dev/null
+++ b/Src/Modules/errnames2.awk
@@ -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 "};"
+}
diff --git a/Src/Modules/system.c b/Src/Modules/system.c
new file mode 100644
index 000000000..174bf133d
--- /dev/null
+++ b/Src/Modules/system.c
@@ -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;
+}
diff --git a/Src/Modules/system.mdd b/Src/Modules/system.mdd
new file mode 100644
index 000000000..61950994a
--- /dev/null
+++ b/Src/Modules/system.mdd
@@ -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
+