diff -crN gawk-3.0.6/Makefile.in gawk-3.0.6+networking/Makefile.in *** gawk-3.0.6/Makefile.in Sun Jun 18 14:14:08 2000 --- gawk-3.0.6+networking/Makefile.in Wed Aug 9 18:55:12 2000 *************** *** 34,40 **** INSTALL_DATA = @INSTALL_DATA@ LDFLAGS = @LDFLAGS@ ! LIBS = @LIBS@ ALLOCA = @ALLOCA@ --- 34,40 ---- INSTALL_DATA = @INSTALL_DATA@ LDFLAGS = @LDFLAGS@ ! LIBS = @SOCKET_LIBS@ @LIBS@ ALLOCA = @ALLOCA@ diff -crN gawk-3.0.6/README.networking gawk-3.0.6+networking/README.networking *** gawk-3.0.6/README.networking Thu Jan 1 01:00:00 1970 --- gawk-3.0.6+networking/README.networking Wed Aug 9 18:55:12 2000 *************** *** 0 **** --- 1,61 ---- + Wed Aug 9 19:06:44 MEST 2000 + + ----------------------------- + This is the patch for gawk 3.0.6. Nothing else has changed. + + Tue Jun 27 15:02:55 MEST 2000 + ----------------------------- + + This is the patch for gawk 3.0.5. Nothing else has changed. + The article in Linux Journal (issue 60, May 1999) is available + online at + + http://noframes.linuxjournal.com/lj-issues/issue60/3132.html + + Unfortunately, the example scripts in the online article have been broken + while copying them into the online versions. They are almost correct, but + not quite. If you do not like such guessing games while learning new + feature of GNU AWK, you can either read the paper version (which is correct), + or read the online tutorial at + + http://home.t-online.de/home/Juergen.Kahrs/inet_toc.html + + Mon Jul 5 16:12:47 IDT 1999 + ---------------------------- + + This version of gawk 3.0.4 contains a set of unofficial patches + that add two way I/O to gawk, and with it, the ability to make TCP + and UDP connections. TCP connections are a better fit for gawk's + I/O model. UDP server code does not work with this patch, although + it does in my development version. I did not have time to trace this + down. + + The basic idea is that you say + + "program" |& getline [var] + + or + + print ... |& "program" + printf ... |& "program" + + The `|&' is borrowed from the ksh syntax to create a co-process. + + Two-way I/O should always be done with |&, and it doesn't matter whether + the first operation is a getline or a print/printf. The connection + is terminated with close(), as usual. + + In addition, if the program name has the form + + /inet/PROTO/LOCAL-PORT/REMOTE-HOST/REMOTE-PORT + + it is for TCP/IP. PROTO is either "tcp" or "udp", and the others + should be obvious. Use 0 as the port if you want the system to assign it. + + For example: + + Service = "/inet/tcp/0/localhost/daytime" + + .... + Service |& getline time + + Juergen Kahrs wrote a Linux Journal article on this feature (Issue 60?). + + I am making this patch available, because gawk 3.1 is nowhere near ready, + but this feature is useful enough that people may want to play with it. + diff -crN gawk-3.0.6/acconfig.h gawk-3.0.6+networking/acconfig.h *** gawk-3.0.6/acconfig.h Wed Jun 7 10:47:25 2000 --- gawk-3.0.6+networking/acconfig.h Wed Aug 9 18:55:12 2000 *************** *** 30,35 **** --- 30,37 ---- #undef SPRINTF_RET /* return type of sprintf */ #undef BITOPS /* bitwise ops (undocumented feature) */ #undef NONDECDATA /* non-decimal input data (undocumented feature) */ + #undef HAVE_SOCKETS /* we have sockets on this system */ + #undef HAVE_PORTALS /* we have portals on /p on this system */ #undef _FILE_OFFSET_BITS /* bits in a file offset, where this matters */ #undef _LARGEFILE_SOURCE /* makes fseeko etc. visible on some hosts */ #undef _LARGE_FILES /* emables large files on AIX-style hosts */ diff -crN gawk-3.0.6/aclocal.m4 gawk-3.0.6+networking/aclocal.m4 *** gawk-3.0.6/aclocal.m4 Mon Jun 12 14:55:50 2000 --- gawk-3.0.6+networking/aclocal.m4 Wed Aug 9 18:55:12 2000 *************** *** 39,44 **** --- 39,106 ---- AC_MSG_RESULT([${gawk_cv_c_stringize}]) ])dnl + dnl Find the socket libraries + dnl largely stolen from AC_PATH_XTRA + AC_DEFUN(GAWK_AC_LIB_SOCKETS, [ + gawk_have_sockets=no + # Check for system-dependent location of socket libraries + + SOCKET_LIBS= + if test "$ISC" = yes; then + SOCKET_LIBS="-lnsl_s -linet" + else + # Martyn.Johnson@cl.cam.ac.uk says this is needed for Ultrix, if the X + # libraries were built with DECnet support. And karl@cs.umb.edu says + # the Alpha needs dnet_stub (dnet does not exist). + # + # ADR: Is this needed just for sockets??? + # AC_CHECK_LIB(dnet, dnet_ntoa, [SOCKET_LIBS="$SOCKET_LIBS -ldnet"]) + # if test $ac_cv_lib_dnet_ntoa = no; then + # AC_CHECK_LIB(dnet_stub, dnet_ntoa, + # [SOCKET_LIBS="$SOCKET_LIBS -ldnet_stub"]) + # fi + + # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, + # to get the SysV transport functions. + # chad@anasazi.com says the Pyramid MIS-ES running DC/OSx (SVR4) + # needs -lnsl. + # The nsl library prevents programs from opening the X display + # on Irix 5.2, according to dickey@clark.net. + AC_CHECK_FUNC(gethostbyname) + if test $ac_cv_func_gethostbyname = no; then + AC_CHECK_LIB(nsl, gethostbyname, SOCKET_LIBS="$SOCKET_LIBS -lnsl") + fi + + # lieder@skyler.mavd.honeywell.com says without -lsocket, + # socket/setsockopt and other routines are undefined under SCO ODT + # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary + # on later versions), says simon@lia.di.epfl.ch: it contains + # gethostby* variants that don't use the nameserver (or something). + # -lsocket must be given before -lnsl if both are needed. + # We assume that if connect needs -lnsl, so does gethostbyname. + AC_CHECK_FUNC(connect) + if test $ac_cv_func_connect = no; then + AC_CHECK_LIB(socket, connect, SOCKET_LIBS="-lsocket $SOCKET_LIBS" + gawk_have_sockets=yes, , + $SOCKET_LIBS) + else + gawk_have_sockets=yes + fi + fi + + if test "${gawk_have_sockets}" = "yes" + then + AC_MSG_CHECKING([where to find the socket library calls]) + case "${SOCKET_LIBS}" in + ?*) gawk_lib_loc="${SOCKET_LIBS}" ;; + *) gawk_lib_loc="the standard library" ;; + esac + AC_MSG_RESULT([${gawk_lib_loc}]) + + AC_DEFINE(HAVE_SOCKETS) + fi + AC_SUBST(SOCKET_LIBS)dnl + ])dnl dnl By default, many hosts won't let programs access large files; dnl one must use special compiler options to get large-file access to work. diff -crN gawk-3.0.6/awk.h gawk-3.0.6+networking/awk.h *** gawk-3.0.6/awk.h Sun Jul 16 15:52:37 2000 --- gawk-3.0.6+networking/awk.h Wed Aug 9 18:55:12 2000 *************** *** 153,158 **** --- 153,162 ---- #include #endif /* atarist || VMS */ + #if ! defined(MSDOS) && ! defined(OS2) + #define O_BINARY 0 + #endif + #if HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ *************** *** 304,309 **** --- 308,314 ---- Node_redirect_pipe, /* subnode is where to redirect */ Node_redirect_pipein, /* subnode is where to redirect */ Node_redirect_input, /* subnode is where to redirect */ + Node_redirect_twoway, /* subnode is where to redirect */ /* Variables */ Node_var, /* rnode is value, lnode is array stuff */ *************** *** 493,501 **** # define IOP_IS_TTY 1 # define IOP_IS_INTERNAL 2 # define IOP_NO_FREE 4 ! # define IOP_MMAPPED 8 ! # define IOP_NOFREE_OBJ 16 ! int (*getrec)(); } IOBUF; typedef void (*Func_ptr)(); --- 498,504 ---- # define IOP_IS_TTY 1 # define IOP_IS_INTERNAL 2 # define IOP_NO_FREE 4 ! # define IOP_NOFREE_OBJ 8 } IOBUF; typedef void (*Func_ptr)(); *************** *** 511,516 **** --- 514,521 ---- # define RED_NOBUF 32 # define RED_USED 64 /* closed temporarily to reuse fd */ # define RED_EOF 128 + # define RED_TWOWAY 256 + # define RED_SOCKET 512 char *value; FILE *fp; FILE *ifp; /* input fp, needed for PIPES_SIMULATED */ diff -crN gawk-3.0.6/awk.y gawk-3.0.6+networking/awk.y *** gawk-3.0.6/awk.y Sun Jul 16 17:29:50 2000 --- gawk-3.0.6+networking/awk.y Wed Aug 9 18:55:12 2000 *************** *** 134,140 **** %left FUNC_CALL LEX_BUILTIN LEX_LENGTH %nonassoc ',' %nonassoc MATCHOP ! %nonassoc RELOP '<' '>' '|' APPEND_OP %left CONCAT_OP %left YSTRING YNUMBER %left '+' '-' --- 134,140 ---- %left FUNC_CALL LEX_BUILTIN LEX_LENGTH %nonassoc ',' %nonassoc MATCHOP ! %nonassoc RELOP '<' '>' '|' APPEND_OP TWOWAYIO %left CONCAT_OP %left YSTRING YNUMBER %left '+' '-' *************** *** 580,585 **** --- 580,587 ---- { $$ = node($2, Node_redirect_append, (NODE *) NULL); } | '|' exp { $$ = node($2, Node_redirect_pipe, (NODE *) NULL); } + | TWOWAYIO exp + { $$ = node($2, Node_redirect_twoway, (NODE *) NULL); } ; opt_param_list *************** *** 678,683 **** --- 680,690 ---- $$ = node($4, Node_K_getline, node($1, Node_redirect_pipein, (NODE *) NULL)); } + | exp TWOWAYIO LEX_GETLINE opt_variable + { + $$ = node($4, Node_K_getline, + node($1, Node_redirect_twoway, (NODE *) NULL)); + } | LEX_GETLINE opt_variable input_redir { if (do_lint && ! io_allowed && $3 == NULL) *************** *** 1787,1792 **** --- 1794,1803 ---- allow_newline(); want_assign = FALSE; return lasttok = LEX_OR; + } else if (! do_traditional && c == '&') { + yylval.nodetypeval = Node_redirect_twoway; + want_assign = FALSE; + return lasttok = TWOWAYIO; } pushback(); return lasttok = '|'; diff -crN gawk-3.0.6/builtin.c gawk-3.0.6+networking/builtin.c *** gawk-3.0.6/builtin.c Sun Jul 16 05:13:57 2000 --- gawk-3.0.6+networking/builtin.c Wed Aug 9 18:55:12 2000 *************** *** 901,906 **** --- 901,908 ---- fp = stdout; tree = do_sprintf(tree->lnode); efwrite(tree->stptr, sizeof(char), tree->stlen, fp, "printf", rp, TRUE); + if (rp != NULL && (rp->flag & RED_TWOWAY) != 0) + fflush(rp->fp); free_temp(tree); } *************** *** 1195,1200 **** --- 1197,1205 ---- } if (ORSlen > 0) efwrite(ORS, sizeof(char), (size_t) ORSlen, fp, "print", rp, TRUE); + + if (rp != NULL && (rp->flag & RED_TWOWAY) != 0) + fflush(rp->fp); free(t); } diff -crN gawk-3.0.6/configh.in gawk-3.0.6+networking/configh.in *** gawk-3.0.6/configh.in Mon Jun 12 14:56:11 2000 --- gawk-3.0.6+networking/configh.in Wed Aug 9 18:55:12 2000 *************** *** 66,74 **** /* Define if you don't have vprintf but do have _doprnt. */ #undef HAVE_DOPRNT - /* Define if you have a working `mmap' system call. */ - #undef HAVE_MMAP - /* Define if your struct stat has st_blksize. */ #undef HAVE_ST_BLKSIZE --- 66,71 ---- *************** *** 133,138 **** --- 130,137 ---- #undef SPRINTF_RET /* return type of sprintf */ #undef BITOPS /* bitwise ops (undocumented feature) */ #undef NONDECDATA /* non-decimal input data (undocumented feature) */ + #undef HAVE_SOCKETS /* we have sockets on this system */ + #undef HAVE_PORTALS /* we have portals on /p on this system */ #undef _FILE_OFFSET_BITS /* bits in a file offset, where this matters */ #undef _LARGEFILE_SOURCE /* makes fseeko etc. visible on some hosts */ #undef _LARGE_FILES /* emables large files on AIX-style hosts */ *************** *** 140,151 **** /* Define if you have the fmod function. */ #undef HAVE_FMOD - /* Define if you have the getpagesize function. */ - #undef HAVE_GETPAGESIZE - - /* Define if you have the madvise function. */ - #undef HAVE_MADVISE - /* Define if you have the memcmp function. */ #undef HAVE_MEMCMP --- 139,144 ---- *************** *** 179,184 **** --- 172,180 ---- /* Define if you have the tzset function. */ #undef HAVE_TZSET + /* Define if you have the header file. */ + #undef HAVE_FCNTL_H + /* Define if you have the header file. */ #undef HAVE_LIMITS_H *************** *** 188,193 **** --- 184,195 ---- /* Define if you have the header file. */ #undef HAVE_MEMORY_H + /* Define if you have the header file. */ + #undef HAVE_NETDB_H + + /* Define if you have the header file. */ + #undef HAVE_NETINET_IN_H + /* Define if you have the header file. */ #undef HAVE_SIGNUM_H *************** *** 202,207 **** --- 204,212 ---- /* Define if you have the header file. */ #undef HAVE_SYS_PARAM_H + + /* Define if you have the header file. */ + #undef HAVE_SYS_SOCKET_H /* Define if you have the header file. */ #undef HAVE_UNISTD_H diff -crN gawk-3.0.6/configure.in gawk-3.0.6+networking/configure.in *** gawk-3.0.6/configure.in Mon Jun 12 14:55:50 2000 --- gawk-3.0.6+networking/configure.in Wed Aug 9 18:55:12 2000 *************** *** 34,39 **** --- 34,40 ---- dnl Additional argument stuff AC_ARG_ENABLE(bitops, [ --enable-bitops Enable Octal and Hex constants and bit functions], AC_DEFINE(BITOPS)) AC_ARG_ENABLE(non-decimal-data, [ --enable-non-decimal-data Enable Octal and Hex constants as valid input data], AC_DEFINE(NONDECDATA)) + AC_ARG_ENABLE(portals, [ --enable-portals Enable /p as path prefix for portals], AC_DEFINE(HAVE_PORTALS)) dnl checks for programs AC_PROG_YACC *************** *** 87,93 **** dnl checks for header files AC_HEADER_STDC AC_HEADER_SYS_WAIT ! AC_CHECK_HEADERS(limits.h locale.h stdarg.h unistd.h signum.h sys/param.h string.h) if test "$ac_cv_header_string_h" = yes then AC_CHECK_HEADERS(memory.h) --- 88,96 ---- dnl checks for header files AC_HEADER_STDC AC_HEADER_SYS_WAIT ! AC_CHECK_HEADERS(fcntl.h limits.h locale.h netdb.h netinet/in.h \ ! signum.h stdarg.h string.h sys/param.h sys/socket.h unistd.h) ! if test "$ac_cv_header_string_h" = yes then AC_CHECK_HEADERS(memory.h) *************** *** 114,127 **** AC_FUNC_VPRINTF AC_CHECK_LIB(m, fmod) ! AC_CHECK_FUNCS(madvise memset memcpy memcmp fmod setlocale strchr strerror \ ! strftime strncasecmp strtod system tzset) ! ! dnl see if we have mmap ! AC_FUNC_MMAP dnl check for how to use getpgrp dnl have to hardwire it for VMS POSIX. Sigh. if (uname) > /dev/null 2>&1 then case `uname` in --- 117,128 ---- AC_FUNC_VPRINTF AC_CHECK_LIB(m, fmod) ! AC_CHECK_FUNCS(memset memcpy memcmp fmod setlocale strchr strerror \ ! strftime strncasecmp strtod system tzset) dnl check for how to use getpgrp dnl have to hardwire it for VMS POSIX. Sigh. + dnl ditto for BeOS. if (uname) > /dev/null 2>&1 then case `uname` in *************** *** 150,155 **** --- 151,159 ---- else AC_FUNC_GETPGRP fi + + dnl check for sockets + GAWK_AC_LIB_SOCKETS dnl checks for structure members AC_STRUCT_ST_BLKSIZE diff -crN gawk-3.0.6/eval.c gawk-3.0.6+networking/eval.c *** gawk-3.0.6/eval.c Sun Jul 16 15:54:12 2000 --- gawk-3.0.6+networking/eval.c Wed Aug 9 18:55:12 2000 *************** *** 221,226 **** --- 221,227 ---- "Node_redirect_pipe", "Node_redirect_pipein", "Node_redirect_input", + "Node_redirect_twoway", "Node_var", "Node_var_array", "Node_val", diff -crN gawk-3.0.6/io.c gawk-3.0.6+networking/io.c *** gawk-3.0.6/io.c Sun Jul 16 05:13:59 2000 --- gawk-3.0.6+networking/io.c Wed Aug 9 18:55:12 2000 *************** *** 24,30 **** */ #include "awk.h" - #undef HAVE_MMAP /* for now, probably forever */ #ifdef HAVE_SYS_PARAM_H #undef RE_DUP_MAX /* avoid spurious conflict w/regex.h */ --- 24,29 ---- *************** *** 35,47 **** #include #endif /* HAVE_SYS_WAIT_H */ - #ifdef HAVE_MMAP - #include - #ifndef MAP_FAILED - #define MAP_FAILED ((caddr_t) -1) - #endif /* ! defined (MAP_FAILED) */ - #endif /* HAVE_MMAP */ - #ifndef O_RDONLY #include #endif --- 34,39 ---- *************** *** 49,54 **** --- 41,56 ---- #define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) #endif + #ifdef HAVE_SYS_SOCKET_H + #include + #endif /* HAVE_SYS_SOCKET_H */ + #ifdef HAVE_NETINET_IN_H + #include + #endif /* HAVE_NETINET_IN_H */ + #ifdef HAVE_NETDB_H + #include + #endif /* HAVE_NETDB_H */ + #if ! defined(S_ISREG) && defined(S_IFREG) #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #endif *************** *** 61,66 **** --- 63,72 ---- #define ENFILE EMFILE #endif + #ifdef HAVE_SOCKETS + enum inet_prot { INET_NONE, INET_TCP, INET_UDP, INET_RAW }; + #endif + #ifdef atarist #include #endif *************** *** 84,97 **** static int gawk_pclose P((struct redirect *rp)); static int do_pathopen P((const char *file)); static int get_a_record P((char **out, IOBUF *iop, int rs, Regexp *RSre, int *errcode)); - #ifdef HAVE_MMAP - static int mmap_get_record P((char **out, IOBUF *iop, int rs, Regexp *RSre, int *errcode)); - #endif /* HAVE_MMAP */ static int str2mode P((const char *mode)); static void spec_setup P((IOBUF *iop, int len, int allocate)); static int specfdopen P((IOBUF *iop, const char *name, const char *mode)); static int pidopen P((IOBUF *iop, const char *name, const char *mode)); static int useropen P((IOBUF *iop, const char *name, const char *mode)); #if defined (HAVE_POPEN_H) #include "popen.h" --- 90,101 ---- static int gawk_pclose P((struct redirect *rp)); static int do_pathopen P((const char *file)); static int get_a_record P((char **out, IOBUF *iop, int rs, Regexp *RSre, int *errcode)); static int str2mode P((const char *mode)); static void spec_setup P((IOBUF *iop, int len, int allocate)); static int specfdopen P((IOBUF *iop, const char *name, const char *mode)); static int pidopen P((IOBUF *iop, const char *name, const char *mode)); static int useropen P((IOBUF *iop, const char *name, const char *mode)); + static int two_way_open P((char *str, struct redirect *rp)); #if defined (HAVE_POPEN_H) #include "popen.h" *************** *** 227,234 **** int retval = 0; if ((cnt = iop->cnt) != EOF) ! cnt = (*(iop->getrec)) ! (&begin, iop, RS->stptr[0], RS_regexp, NULL); if (cnt == EOF) { cnt = 0; retval = 1; --- 231,237 ---- int retval = 0; if ((cnt = iop->cnt) != EOF) ! cnt = get_a_record(&begin, iop, RS->stptr[0], RS_regexp, NULL); if (cnt == EOF) { cnt = 0; retval = 1; *************** *** 271,278 **** /* Don't close standard files or else crufty code elsewhere will lose */ if (iop->fd == fileno(stdin) || iop->fd == fileno(stdout) ! || iop->fd == fileno(stderr) ! || (iop->flag & IOP_MMAPPED) != 0) ret = 0; else ret = close(iop->fd); --- 274,280 ---- /* Don't close standard files or else crufty code elsewhere will lose */ if (iop->fd == fileno(stdin) || iop->fd == fileno(stdout) ! || iop->fd == fileno(stderr)) ret = 0; else ret = close(iop->fd); *************** *** 297,308 **** fields_arr[0] = t; reset_record(); } ! if ((iop->flag & IOP_MMAPPED) == 0) ! free(iop->buf); ! #ifdef HAVE_MMAP ! else ! (void) munmap(iop->buf, iop->size); ! #endif } if ((iop->flag & IOP_NOFREE_OBJ) == 0) free((char *) iop); --- 299,305 ---- fields_arr[0] = t; reset_record(); } ! free(iop->buf); } if ((iop->flag & IOP_NOFREE_OBJ) == 0) free((char *) iop); *************** *** 374,381 **** tflag = (RED_FILE|RED_READ); what = "<"; break; default: ! fatal("invalid tree type %d in redirect()", tree->type); break; } tmp = tree_eval(tree->subnode); --- 371,382 ---- tflag = (RED_FILE|RED_READ); what = "<"; break; + case Node_redirect_twoway: + tflag = (RED_READ|RED_WRITE|RED_TWOWAY); + what = "|&"; + break; default: ! fatal("invalid tree type %s in redirect()", nodetype2str(tree->type)); break; } tmp = tree_eval(tree->subnode); *************** *** 392,404 **** if (do_lint && (STREQN(str, "0", tmp->stlen) || STREQN(str, "1", tmp->stlen))) warning("filename `%s' for `%s' redirection may be result of logical expression", str, what); ! for (rp = red_head; rp != NULL; rp = rp->next) if (strlen(rp->value) == tmp->stlen && STREQN(rp->value, str, tmp->stlen) && ((rp->flag & ~(RED_NOBUF|RED_EOF)) == tflag || (outflag != 0 ! && (rp->flag & (RED_FILE|RED_WRITE)) == outflag))) break; if (rp == NULL) { emalloc(rp, struct redirect *, sizeof(struct redirect), "redirect"); --- 393,417 ---- if (do_lint && (STREQN(str, "0", tmp->stlen) || STREQN(str, "1", tmp->stlen))) warning("filename `%s' for `%s' redirection may be result of logical expression", str, what); ! ! if (STREQN(str, "/inet/", 6)) ! tflag |= RED_SOCKET; ! ! for (rp = red_head; rp != NULL; rp = rp->next) { if (strlen(rp->value) == tmp->stlen && STREQN(rp->value, str, tmp->stlen) && ((rp->flag & ~(RED_NOBUF|RED_EOF)) == tflag || (outflag != 0 ! && (rp->flag & (RED_FILE|RED_WRITE)) == outflag))) { ! if (do_lint && rp->flag != tflag) ! warning( ! "unnecessary mixing of `>' and `>>' for file `%.*s'", ! tmp->stlen, rp->value); ! break; + } + } + if (rp == NULL) { emalloc(rp, struct redirect *, sizeof(struct redirect), "redirect"); *************** *** 419,424 **** --- 432,438 ---- red_head = rp; } else str = rp->value; /* get \0 terminated string */ + while (rp->fp == NULL && rp->iop == NULL) { if (rp->flag & RED_EOF) /* *************** *** 456,461 **** --- 470,485 ---- direction = "from"; rp->iop = iop_open(str, "r", NULL); break; + case Node_redirect_twoway: + direction = "to/from"; + if (two_way_open(str, rp) == FALSE) + fatal("can't open two way %s (\"%s\") for input/output (%s)", + #ifdef HAVE_SOCKETS + STREQN(str, "/inet/", 6) ? "socket" : + #endif + "pipe", + str, strerror(errno)); + break; default: cant_happen(); } *************** *** 627,633 **** if (rp->fp == stdout || rp->fp == stderr) return 0; errno = 0; ! if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE)) status = pclose(rp->fp); else if (rp->fp != NULL) status = fclose(rp->fp); --- 651,666 ---- if (rp->fp == stdout || rp->fp == stderr) return 0; errno = 0; ! if ((rp->flag & RED_TWOWAY) != 0) { ! if (rp->fp != NULL) ! status = fclose(rp->fp); ! if ((rp->flag & RED_SOCKET) != 0) ! (void) iop_close(rp->iop); ! else ! (void) gawk_pclose(rp); ! rp->iop = NULL; ! rp->fp = NULL; ! } else if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE)) status = pclose(rp->fp); else if (rp->fp != NULL) status = fclose(rp->fp); *************** *** 749,775 **** --- 782,937 ---- const char *mode; { int ret; + const char *second = & mode[1]; + + if (*second == 'b') + second++; switch(mode[0]) { case 'r': ret = O_RDONLY; + if (*second == '+' || *second == 'w') + ret = O_RDWR; break; case 'w': ret = O_WRONLY|O_CREAT|O_TRUNC; + if (*second == '+' || *second == 'r') + ret = O_RDWR|O_CREAT|O_TRUNC; break; case 'a': ret = O_WRONLY|O_APPEND|O_CREAT; + if (*second == '+') + ret = O_RDWR|O_APPEND|O_CREAT; break; default: ret = 0; /* lint */ cant_happen(); } + if (strchr(mode, 'b') != NULL) + ret |= O_BINARY; return ret; } + #ifdef HAVE_SOCKETS + /* socketopen --- open a socket and set it into connected state */ + + int + socketopen(type, localport, remoteport, remotehostname) + enum inet_prot type; + int localport; + int remoteport; + char *remotehostname; + { + struct hostent *hp = gethostbyname(remotehostname); + struct sockaddr_in local_addr, remote_addr; + int socket_fd; + int any_remote_host = strcmp(remotehostname, "0"); + + socket_fd = INVALID_HANDLE; + switch (type) { + case INET_TCP: + if (localport != 0 || remoteport != 0) { + struct linger linger; + int on = 1; + + memset(& linger, '\0', sizeof(linger)); + socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, + (const char *) & on, sizeof(on)); + linger.l_onoff = 1; + linger.l_linger = 30; /* linger for 30/100 second */ + setsockopt(socket_fd, SOL_SOCKET, SO_LINGER, + (const char *) & linger, sizeof(linger)); + } + break; + case INET_UDP: + if (localport != 0 || remoteport != 0) + socket_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + break; + case INET_RAW: + if (localport == 0 && remoteport == 0) + socket_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); + break; + case INET_NONE: + /* fall through */ + default: + cant_happen(); + break; + } + + if (socket_fd < 0 || socket_fd == INVALID_HANDLE + || (hp == NULL && any_remote_host != 0)) + return INVALID_HANDLE; + + local_addr.sin_family = remote_addr.sin_family = AF_INET; + local_addr.sin_addr.s_addr = htonl(INADDR_ANY); + remote_addr.sin_addr.s_addr = htonl(INADDR_ANY); + local_addr.sin_port = htons(localport); + remote_addr.sin_port = htons(remoteport); + if (bind(socket_fd, (struct sockaddr *) &local_addr, sizeof(local_addr)) == 0) { + if (any_remote_host != 0) { /* not ANY => create a client */ + if (type == INET_TCP || type == INET_UDP) { + memcpy(&remote_addr.sin_addr, hp->h_addr, + sizeof(remote_addr.sin_addr)); + if (connect(socket_fd, + (struct sockaddr *) &remote_addr, + sizeof(remote_addr)) != 0) { + close(socket_fd); + if (localport == 0) + socket_fd = INVALID_HANDLE; + else + socket_fd = socketopen(type, localport, 0, ""); + } + } else { + /* /inet/raw client not ready yet */ + fatal("/inet/raw client not ready yet, sorry"); + } + } else { /* remote host is ANY => create a server */ + if (type == INET_TCP) { + int clientsocket_fd = INVALID_HANDLE; + int namelen = sizeof(remote_addr); + + if (listen(socket_fd, 1) >= 0 + && (clientsocket_fd = accept(socket_fd, + (struct sockaddr *) &remote_addr, + &namelen)) >= 0) { + close(socket_fd); + socket_fd = clientsocket_fd; + } else { + close(socket_fd); + socket_fd = INVALID_HANDLE; + } + } else if (type == INET_UDP) { + char buf[10]; + int readle; + + if (recvfrom(socket_fd, buf, 1, MSG_PEEK, + (struct sockaddr *) & remote_addr, + & readle) < 1 + || readle != sizeof(remote_addr) + || connect(socket_fd, + (struct sockaddr *)& remote_addr, + readle) != 0) { + close(socket_fd); + socket_fd = INVALID_HANDLE; + } + } else { + /* /inet/raw server not ready yet */ + fatal("/inet/raw server not ready yet, sorry"); + } + } + } else { + close(socket_fd); + socket_fd = INVALID_HANDLE; + } + + return socket_fd; + } + #endif /* HAVE_SOCKETS */ + /* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */ /* *************** *** 800,811 **** if (do_traditional) goto strictopen; ! if ((openfd = os_devopen(name, flag)) >= 0) return openfd; ! if (STREQN(name, "/dev/", 5) && stat((char *) name, &buf) == -1) { cp = name + 5; ! if (STREQ(cp, "stdin") && (flag & O_ACCMODE) == O_RDONLY) openfd = fileno(stdin); else if (STREQ(cp, "stdout") && (flag & O_ACCMODE) == O_WRONLY) --- 962,973 ---- if (do_traditional) goto strictopen; ! if ((openfd = os_devopen(name, flag)) != INVALID_HANDLE) return openfd; ! if (STREQN(name, "/dev/", 5)) { cp = name + 5; ! if (STREQ(cp, "stdin") && (flag & O_ACCMODE) == O_RDONLY) openfd = fileno(stdin); else if (STREQ(cp, "stdout") && (flag & O_ACCMODE) == O_WRONLY) *************** *** 818,823 **** --- 980,1080 ---- if (openfd <= INVALID_HANDLE || ptr == cp) openfd = INVALID_HANDLE; } + if (openfd != INVALID_HANDLE) + return openfd; + } else if (STREQN(name, "/inet/", 6)) { + #ifdef HAVE_SOCKETS + /* /inet/protocol/localport/hostname/remoteport */ + enum inet_prot protocol = INET_NONE; + int localport, remoteport, i; + char hostname[200] = ""; + char proto[10], item [200]; + struct servent *service; + + cp = name + 6; + /* which protocol ? */ + if (STREQN(cp, "tcp/", 4)) + protocol = INET_TCP; + else if (STREQN(cp, "udp/", 4)) + protocol = INET_UDP; + else if (STREQN(cp, "raw/", 4)) + protocol = INET_RAW; + else + fatal("no (known) protocol supplied in special filename `%s'", + name); + + strncpy(proto, cp, 3); + proto[3] = '\0'; + cp += 4; + + /* which localport ? */ + for (i = 0; *cp != '/' && *cp != '\0'; cp++) + item[i++] = *cp; + + if (*cp == '/') + cp++; + item[i] = '\0'; + + /* + * Require a port, let them explicitly put 0 if + * they don't care. + */ + localport = 0; /* turn off compiler warnings */ + if (i == 0) + fatal("must supply a local port to `/inet'"); + else { + localport = atoi(item); + if (localport <= 0 || localport > 65535) { + service = getservbyname(item, proto); + if (service == NULL) + localport = 0; + else + localport = ntohs(service->s_port); + } + } + + /* which hostname ? */ + for (i = 0; *cp != '/' && *cp != '\0'; cp++) + hostname[i++] = *cp; + + if (*cp == '/') + cp++; + hostname[i] = '\0'; + + if (i == 0) + fatal("must supply a remote hostname to `/inet'"); + + /* which remoteport ? */ + for (i = 0; *cp != '/' && *cp != '\0'; cp++) + item[i++] = *cp; + + if (*cp == '/') + cp++; + item[i] = '\0'; + + /* + * Here too, require a port, let them explicitly put 0 if + * they don't care. + */ + remoteport = 0; /* turn off compiler warnings */ + if (i == 0) + fatal("must supply a remote port to `/inet'"); + else { + remoteport = atoi(item); + if (remoteport <= 0 || remoteport > 65535) { + service = getservbyname(item, proto); + if (service == NULL) + remoteport = 0; + else + remoteport = ntohs(service->s_port); + } + } + + /* Open Sesame! */ + openfd = socketopen(protocol, localport, remoteport, hostname); + #else /* ! HAVE_SOCKETS */ + fatal("TCP/IP communications are not supported"); + #endif /* HAVE_SOCKETS */ } strictopen: *************** *** 855,861 **** iop->end = iop->buf + len; iop->fd = -1; iop->flag = IOP_IS_INTERNAL; - iop->getrec = get_a_record; } /* specfdopen --- open an fd special file */ --- 1112,1117 ---- *************** *** 978,983 **** --- 1234,1240 ---- { "/dev/stdin", 10, specfdopen }, { "/dev/stdout", 11, specfdopen }, { "/dev/stderr", 11, specfdopen }, + { "/inet/", 6, specfdopen }, { "/dev/pid", 8, pidopen }, { "/dev/ppid", 9, pidopen }, { "/dev/pgrpid", 11, pidopen }, *************** *** 987,1001 **** flag = str2mode(mode); - /* - * FIXME: remove the stat call, and always process these files - * internally. - */ if (STREQ(name, "-")) openfd = fileno(stdin); else if (do_traditional) goto strictopen; ! else if (STREQN(name, "/dev/", 5) && stat((char *) name, &buf) == -1) { int i; for (i = 0; i < devcount; i++) { --- 1244,1254 ---- flag = str2mode(mode); if (STREQ(name, "-")) openfd = fileno(stdin); else if (do_traditional) goto strictopen; ! else if (STREQN(name, "/dev/", 5) || STREQN(name, "/inet/", 6)) { int i; for (i = 0; i < devcount; i++) { *************** *** 1125,1130 **** --- 1378,1520 ---- return (rp->status >> 8) & 0xFF; } + /* two_way_open --- open a two way communications channel */ + + static int + two_way_open(str, rp) + char *str; + struct redirect *rp; + { + int fd; + int ptoc[2], ctop[2]; + int pid; + int save_errno; + int newfd; + + /* case 1: socket */ + if (STREQN(str, "/inet/", 6)) { + fd = devopen(str, "rw"); + if (fd == INVALID_HANDLE) + return FALSE; + rp->fp = fdopen(fd, "w"); + if (rp->fp == NULL) { + close(fd); + return FALSE; + } + newfd = dup(fd); + if (newfd < 0) { + fclose(rp->fp); + return FALSE; + } + rp->iop = iop_alloc(newfd, str, NULL); + if (rp->iop == NULL) { + fclose(rp->fp); + return FALSE; + } + rp->flag |= RED_SOCKET; + return TRUE; + } + #ifdef HAVE_PORTALS + if (STREQN(str, "/p/", 3)) { + fd = open(str, O_RDWR); + if (fd == INVALID_HANDLE) + return FALSE; + rp->fp = fdopen(fd, "w"); + if (rp->fp == NULL) { + close(fd); + return FALSE; + } + newfd = dup(fd); + if (newfd < 0) { + fclose(rp->fp); + return FALSE; + } + rp->iop = iop_alloc(newfd, str, NULL); + if (rp->iop == NULL) { + fclose(rp->fp); + return FALSE; + } + rp->flag |= RED_SOCKET; + return TRUE; + } + #endif /* HAVE_PORTALS */ + + /* case 2: two way pipe to a child process */ + if (pipe(ptoc) < 0) + return FALSE; /* errno set, diagnostic from caller */ + + if (pipe(ctop) < 0) { + save_errno = errno; + close(ptoc[0]); + close(ptoc[1]); + errno = save_errno; + return FALSE; + } + + if ((pid = fork()) < 0) { + save_errno = errno; + close(ptoc[0]); close(ptoc[1]); + close(ctop[0]); close(ctop[1]); + errno = save_errno; + return FALSE; + } + + if (pid == 0) { /* child */ + if (close(1) == -1) + fatal("close of stdout in child failed (%s)", + strerror(errno)); + if (dup(ctop[1]) != 1) + fatal("dup of output pipe failed (%s)", strerror(errno)); + if (close(0) == -1) + fatal("close of stdin in child failed (%s)", + strerror(errno)); + if (dup(ptoc[0]) != 0) + fatal("dup of input pipe failed (%s)", strerror(errno)); + if ( close(ptoc[0]) == -1 || close(ptoc[1]) == -1 + || close(ctop[0]) == -1 || close(ctop[1]) == -1) + fatal("close of pipe failed (%s)", strerror(errno)); + /* FIXME: Should stderr get dup'ed onto child's stdout? */ + execl("/bin/sh", "sh", "-c", str, NULL); + _exit(127); + } + + /* parent */ + rp->pid = pid; + rp->iop = iop_alloc(ctop[0], str, NULL); + if (rp->iop == NULL) { + (void) close(ctop[0]); + (void) close(ctop[1]); + (void) close(ptoc[0]); + (void) close(ptoc[1]); + (void) kill(pid, SIGKILL); /* overkill? (pardon pun) */ + return FALSE; + } + rp->fp = fdopen(ptoc[1], "w"); + if (rp->fp == NULL) { + iop_close(rp->iop); + rp->iop = NULL; + (void) close(ctop[0]); + (void) close(ctop[1]); + (void) close(ptoc[0]); + (void) close(ptoc[1]); + (void) kill(pid, SIGKILL); /* overkill? (pardon pun) */ + return FALSE; + } + if (fcntl(ctop[0], F_SETFD, 1) < 0) { + warning("%s:%d: pipe from `%s': could not set close-on-exec: %s", + __FILE__, __LINE__, + str, strerror(errno));; + } + if (fcntl(ptoc[1], F_SETFD, 1) < 0) { + warning("%s:%d: pipe to `%s': could not set close-on-exec: %s", + __FILE__, __LINE__, + str, strerror(errno));; + } + (void) close(ptoc[0]); + (void) close(ctop[1]); + return TRUE; + } + #else /* PIPES_SIMULATED */ /* *************** *** 1226,1231 **** --- 1616,1632 ---- } #endif /* not (VMS || OS2 || MSDOS) */ + /* two_way_open --- open a two way communications channel */ + + int + two_way_open(str, rp) + char *str; + struct redirect *rp; + { + fatal("`|&' not supported"); + /*NOTREACHED*/` + } + #endif /* PIPES_SIMULATED */ /* do_getline --- read in a line, into var and with redirection, as needed */ *************** *** 1264,1270 **** return tmp_number((AWKNUM) 0.0); } errcode = 0; ! cnt = (*(iop->getrec))(&s, iop, RS->stptr[0], RS_regexp, &errcode); if (errcode != 0) { if (! do_traditional) { s = strerror(errcode); --- 1665,1671 ---- return tmp_number((AWKNUM) 0.0); } errcode = 0; ! cnt = get_a_record(&s, iop, RS->stptr[0], RS_regexp, &errcode); if (errcode != 0) { if (! do_traditional) { s = strerror(errcode); *************** *** 1281,1287 **** * reading from a pipe; otherwise * gawk_pclose will not be called. */ ! if ((rp->flag & RED_PIPE) == 0) { (void) iop_close(iop); rp->iop = NULL; } --- 1682,1688 ---- * reading from a pipe; otherwise * gawk_pclose will not be called. */ ! if ((rp->flag & (RED_PIPE|RED_TWOWAY)) == 0) { (void) iop_close(iop); rp->iop = NULL; } *************** *** 1444,1495 **** iop->off = iop->buf = NULL; iop->cnt = 0; iop->name = name; - iop->getrec = get_a_record; - #ifdef HAVE_MMAP - /* Use mmap only for regular files with positive sizes. - The size must fit into size_t, so that mmap works correctly. - Also, it must fit into int, so that iop->cnt won't overflow. */ - if (S_ISREG(sbuf.st_mode) && sbuf.st_size > 0 - && sbuf.st_size == (size_t) sbuf.st_size - && sbuf.st_size == (int) sbuf.st_size) { - register char *cp; - - iop->buf = iop->off = mmap((caddr_t) 0, sbuf.st_size, - PROT_READ|PROT_WRITE, MAP_PRIVATE, - fd, 0L); - /* cast is for buggy compilers (e.g. DEC OSF/1) */ - if (iop->buf == (caddr_t)MAP_FAILED) { - iop->buf = iop->off = NULL; - goto out; - } - - iop->flag |= IOP_MMAPPED; - iop->size = sbuf.st_size; - iop->secsiz = 0; - iop->end = iop->buf + iop->size; - iop->cnt = sbuf.st_size; - iop->getrec = mmap_get_record; - (void) close(fd); - iop->fd = INVALID_HANDLE; - - #if defined(HAVE_MADVISE) && defined(MADV_SEQUENTIAL) - madvise(iop->buf, iop->size, MADV_SEQUENTIAL); - #endif - /* - * The following is a really gross hack. - * We want to ensure that we have a copy of the input - * data that won't go away, on the off chance that someone - * will truncate the data file we've just mmap'ed. - * So, we go through and touch each page, forcing the - * system to give us a private copy. A page size of 512 - * guarantees this will work, even on the least common - * denominator system (like, oh say, a VAX). - */ - for (cp = iop->buf; cp < iop->end; cp += 512) - *cp = *cp; - } - out: - #endif /* HAVE_MMAP */ return iop; } --- 1845,1850 ---- *************** *** 1809,1953 **** return 0; } #endif - - #ifdef HAVE_MMAP - /* mmap_get_record --- pull a record out of a memory-mapped file */ - - static int - mmap_get_record(out, iop, grRS, RSre, errcode) - char **out; /* pointer to pointer to data */ - IOBUF *iop; /* input IOP */ - register int grRS; /* first char in RS->stptr */ - Regexp *RSre; /* regexp for RS */ - int *errcode; /* pointer to error variable */ - { - register char *bp = iop->off; - char *start = iop->off; /* beginning of record */ - int rs; - static Regexp *RS_null_re = NULL; - Regexp *rsre = NULL; - int onecase; - register char *end = iop->end; - int cnt; - - /* first time through */ - if (RS_null_re == NULL) { - RS_null_re = make_regexp("\n\n+", 3, TRUE, TRUE); - if (RS_null_re == NULL) - fatal("internal error: file `%s', line %d\n", - __FILE__, __LINE__); - } - - if (iop->off >= iop->end) { /* previous record was last */ - *out = NULL; - set_RT_to_null(); - iop->cnt = EOF; /* tested by higher level code */ - return EOF; - } - - if (RS_is_null) /* special case: RS == "" */ - rs = '\n'; - else - rs = (char) grRS; - - onecase = (IGNORECASE && isalpha(rs)); - if (onecase) - rs = casetable[rs]; - - /* if RS = "", skip leading newlines at the front of the file */ - if (RS_is_null && iop->off == iop->buf) { - for (bp = iop->off; *bp == '\n'; bp++) - continue; - - if (bp != iop->off) - iop->off = start = bp; - } - - /* - * Regexp based searching. Either RS = "" or RS = - * See comments in get_a_record. - */ - if (! do_traditional && RSre != NULL) /* regexp */ - rsre = RSre; - else if (RS_is_null) /* RS = "" */ - rsre = RS_null_re; - else - rsre = NULL; - - /* - * Look for regexp match of RS. Non-match conditions are: - * 1. No match at all - * 2. Match of a null string - * 3. Match ends at exact end of buffer - * - * #1 means that the record ends the file - * and there is no text that actually matched RS. - * - * #2: is probably like #1. - * - * #3 is simple; since we have the whole file mapped, it's - * the last record in the file. - */ - if (rsre != NULL) { - if (research(rsre, start, 0, iop->end - start, TRUE) == -1 - || RESTART(rsre, start) == REEND(rsre, start)) { - /* no matching text, we have the record */ - *out = start; - iop->off = iop->end; /* all done with the record */ - set_RT_to_null(); - /* special case, don't allow trailing newlines */ - if (RS_is_null && *(iop->end - 1) == '\n') - return iop->end - start - 1; - else - return iop->end - start; - - } - /* have a match */ - *out = start; - bp = start + RESTART(rsre, start); - set_RT(bp, REEND(rsre, start) - RESTART(rsre, start)); - *bp = '\0'; - iop->off = start + REEND(rsre, start); - return bp - start; - } - - /* - * RS = "?", i.e., one character based searching. - * - * Alas, we can't just plug the sentinel character in at - * the end of the mmapp'ed file ( *(iop->end) = rs; ). This - * works if we're lucky enough to have a file that does not - * take up all of its last disk block. But if we end up with - * file whose size is an even multiple of the disk block size, - * assigning past the end of it delivers a SIGBUS. So, we have to - * add the extra test in the while loop at the front that looks - * for going past the end of the mapped object. Sigh. - */ - /* search for RS, #2, RS = */ - if (onecase) { - while (bp < end && casetable[*bp++] != rs) - continue; - } else { - while (bp < end && *bp++ != rs) - continue; - } - cnt = (bp - start) - 1; - if (bp >= iop->end) { - /* at end, may have actually seen rs, or may not */ - if (*(bp-1) == rs) - set_RT(bp - 1, 1); /* real RS seen */ - else { - cnt++; - set_RT_to_null(); - } - } else - set_RT(bp - 1, 1); - - iop->off = bp; - *out = start; - return cnt; - } - #endif /* HAVE_MMAP */ /* set_RS --- update things as appropriate when RS is set */ --- 2164,2169 ---- diff -crN gawk-3.0.6/main.c gawk-3.0.6+networking/main.c *** gawk-3.0.6/main.c Wed Jun 7 11:44:09 2000 --- gawk-3.0.6+networking/main.c Wed Aug 9 18:55:12 2000 *************** *** 735,741 **** static void version() { ! printf("%s.%d\n", version_string, PATCHLEVEL); /* * Per GNU coding standards, print copyright info, * then exit successfully, do nothing else. --- 735,741 ---- static void version() { ! printf("%s.%d + UNOFFICIAL NETWORKING PATCH\n", version_string, PATCHLEVEL); /* * Per GNU coding standards, print copyright info, * then exit successfully, do nothing else. diff -crN gawk-3.0.6/test/Makefile.in gawk-3.0.6+networking/test/Makefile.in *** gawk-3.0.6/test/Makefile.in Thu Aug 3 23:51:51 2000 --- gawk-3.0.6+networking/test/Makefile.in Wed Aug 9 18:55:12 2000 *************** *** 67,76 **** messages:: @$(AWK) -f $(srcdir)/messages.awk >out2 2>out3 ! { $(CMP) $(srcdir)/out1.ok out1 && $(CMP) $(srcdir)/out2.ok out2 && \ ! $(CMP) $(srcdir)/out3.ok out3 && rm -f out1 out2 out3; } || \ ! { { test -d /dev/fd || test -d /proc/self/fd; } && \ ! echo IT IS OK THAT THIS TEST FAILED; } argarray:: @case $(srcdir) in \ --- 67,73 ---- messages:: @$(AWK) -f $(srcdir)/messages.awk >out2 2>out3 ! $(CMP) $(srcdir)/out1.ok out1 && $(CMP) $(srcdir)/out2.ok out2 && $(CMP) $(srcdir)/out3.ok out3 && rm -f out1 out2 out3 argarray:: @case $(srcdir) in \