From 72874ac6d2e803d84f04dced58cb0e5c8afa3651 Mon Sep 17 00:00:00 2001 From: Andy Spencer Date: Tue, 24 Jan 2012 09:51:40 +0000 Subject: [PATCH] Add select --- .gitignore | 3 ++ mkfile | 14 ++++- select.awk | 33 ++++++++++++ select.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++ testirc.lib | 10 ++++ 5 files changed, 207 insertions(+), 2 deletions(-) create mode 100644 select.awk create mode 100644 select.c create mode 100644 testirc.lib diff --git a/.gitignore b/.gitignore index b72f9be..5251d1c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ *~ *.swp +*.so +*.o +config.h diff --git a/mkfile b/mkfile index 4f52cb2..138af83 100644 --- a/mkfile +++ b/mkfile @@ -1,4 +1,14 @@ -test:Q: - awk -f rhawk < testirc.txt +CFLAGS = -g -Wall -fPIC --std=c99 +CPPFLAGS = -I/usr/include/awk -I. -DHAVE_CONFIG_H + +test:Q: select.so + awk -f select.awk + #awk -f rhawk < testirc.txt #awk -f rhawk < testirc.txt #awk -f test.awk test.txt | awk -f rhawk #| grep 'points\|bid\|took' + +%.so: %.o + gcc $CFLAGS -shared -o $target $prereq $LDFLAGS + +%.o: %.c + gcc $CPPFLAGS $CFLAGS -c -o $target $prereq diff --git a/select.awk b/select.awk new file mode 100644 index 0000000..5b45a7a --- /dev/null +++ b/select.awk @@ -0,0 +1,33 @@ +BEGIN { + extension("./select.so", "dlload"); + + nc0 = "netcat -l -p 12345" + nc1 = "netcat -l -p 54321" + stdin = "/dev/stdin" + + while (1) { + # Open pipes + printf "" |& nc0 + printf "" |& nc1 + + # Wait for input + if (!(fd = select("from", stdin, nc0, nc1))) { + print "timeout" + continue + } + + # Read a line + if (fd == stdin) + if (!(st = getline line < fd)) + exit 0 + if (fd == nc0 || fd == nc1) + if (!(st = fd |& getline line)) { + print "broken pipe" + close(fd) + continue + } + + # Print output + print "line: [" fd "] -> [" line "]" + } +} diff --git a/select.c b/select.c new file mode 100644 index 0000000..d379167 --- /dev/null +++ b/select.c @@ -0,0 +1,149 @@ +/* + * select.c - Provide select functions for gawk. + */ + +/* + * Copyright (C) 2012 Andy Spencer + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "awk.h" + +int plugin_is_GPL_compatible; + +/* Select function: + * select(how, [timeout,] fd, ..) + * type = {to,from,error,any} */ +static NODE *do_select(int nargs) +{ + /* Parse arguments */ + if (do_lint && get_curfunc_arg_count() < 2) + lintwarn("select: not enough arguments"); + + /* - check how */ + int read = 0, write = 0, except = 0; + NODE *node = get_scalar_argument(0, FALSE); + NODE *how = force_string(node); + if (!strcmp("to", how->stptr)) write = 1; + if (!strcmp("from", how->stptr)) read = 1; + if (!strcmp("error", how->stptr)) except = 1; + if (!strcmp("any", how->stptr)) read = write = except = 1; + if (!read && !write && !except) { + printf("select: invalid select type: %.*s\n", + how->stlen, how->stptr); + return make_number((AWKNUM) -EINVAL); + } + + /* - check timeout */ + int first = 1; + struct timeval _timeout = {.tv_sec = 1, .tv_usec = 0}; + struct timeval *timeout = &_timeout; + NODE *next = get_scalar_argument(1, FALSE); + if (next->type == Node_val && next->flags & NUMBER) { + AWKNUM num = force_number(next); + if (num < 0) { + timeout = NULL; + } else { + _timeout.tv_sec = (int)num; + _timeout.tv_usec = (num - (int)num) * 1E6; + printf("timeout -> %lf %ld,%ld\n", num, + _timeout.tv_sec, + _timeout.tv_usec); + } + first = 2; + } + + /* Clear fds */ + int nfds = 0; + fd_set readfds, writefds, exceptfds; + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&exceptfds); + + /* Set fds */ + for (int i = first; i < nargs; i++) { + NODE *node = get_scalar_argument(i, TRUE); + if (node == NULL) + continue; + NODE *str = force_string(node); + struct redirect *redir = + getredirect(str->stptr, str->stlen); + if (redir == NULL) { + int err = 0; + int type = read && write ? redirect_twoway : + read ? redirect_input : + write ? redirect_output : 0 ; + redir = redirect(str, type, &err); + } + if (redir == NULL) { + lintwarn("select: arg %d is not a redirect", i); + continue; + } + if ((read || except) && redir->iop->fd >= 0) { + int fd = redir->iop->fd; + if (read) FD_SET(fd, &readfds); + if (except) FD_SET(fd, &exceptfds); + if (fd > nfds) nfds = fd; + } + if ((write || except) && redir->fp) { + int fd = fileno(redir->fp); + if (write) FD_SET(fd, &writefds); + if (except) FD_SET(fd, &exceptfds); + if (fd > nfds) nfds = fd; + } + } + + /* Select fds */ + int rval = select(nfds+1, &readfds, &writefds, &exceptfds, timeout); + if (rval == 0) + return make_number((AWKNUM) 0); + if (rval == -1) + return make_number((AWKNUM) 0); + + /* Return */ + for (int i = first; i < nargs; i++) { + NODE *node = get_scalar_argument(i, TRUE); + if (node == NULL) + continue; + NODE *str = force_string(node); + struct redirect *redir = + getredirect(str->stptr, str->stlen); + if (redir == NULL) + continue; + if ((read || except) && redir->iop->fd >= 0) { + int fd = redir->iop->fd; + if ((read && FD_ISSET(fd, &readfds)) || + (except && FD_ISSET(fd, &writefds))) + return node; + } + if ((write || except) && redir->fp) { + int fd = fileno(redir->fp); + if ((write && FD_ISSET(fd, &writefds)) || + (except && FD_ISSET(fd, &exceptfds))) + return node; + } + } + + /* Error */ + return make_number((AWKNUM) 0); +} + +/* Load select function */ +NODE *dlload(NODE *tree, void *dl) +{ + make_builtin("select", do_select, 99); + return make_number((AWKNUM) 0); +} diff --git a/testirc.lib b/testirc.lib new file mode 100644 index 0000000..c215010 --- /dev/null +++ b/testirc.lib @@ -0,0 +1,10 @@ +:andy753421!~a@c.d TOPIC #sfvlug :San Fernando Valley Linux Users Group | Meeting: Sat January 21, 6:00pm Denny's Van Nuys | Website: www.sfvlug.org & Wiki: http://tinyurl.com/tabrr & Meetup: http://meetup.com/sfvlug | Knowledge is power. http://tinyurl.com/2xr7sd +:andy753421!~a@c.d PRIVMSG #sfvlug :.poll +PING :hitchcock.freenode.net +:hitchcock.freenode.net PONG hitch +:andy753421!~andy@rhlug/a PRIVMSG #rhnoise :hm... +:andy753421!~andy@rhlug/a PRIVMSG #rhnoise :gah, bloody oddly formatted commands +:rhawk!~andy@76-219-180-192.lightspeed.irvnca.sbcglobal.net JOIN #rhnoise +:hitchcock.freenode.net 332 rhawk #rhnoise : ooh, an occupy austin mariachi is going on outside +:andy753421!~andy@rhlug/a KICK #rhnoise beausoleil :beausoleil +:hitchcock.freenode.net 332 rhawk #rhnoise : ooh, an occupy austin mariachi is going on outside -- 2.43.2