]> Pileus Git - ~andy/rhawk/blob - select.c
Add limit to tied message
[~andy/rhawk] / select.c
1 /*
2  * select.c - Provide select functions for gawk.
3  */
4
5 /*
6  * Copyright (C) 2012 Andy Spencer
7  *
8  * GAWK is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * GAWK is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
21  */
22
23 #include <awk.h>
24
25 int plugin_is_GPL_compatible;
26
27 /* Select function:
28  *   select(how, [timeout,] fd, ..)
29  *   type = {to,from,error,any} */
30 static NODE *do_select(int nargs)
31 {
32         /* Parse arguments */
33         if (do_lint && get_curfunc_arg_count() < 2)
34                 lintwarn("select: not enough arguments");
35
36         /* - check how */
37         int read = 0, write = 0, except = 0;
38         NODE *node = get_scalar_argument(0, FALSE);
39         NODE *how  = force_string(node);
40         if (!strcmp("to",    how->stptr)) write  = 1;
41         if (!strcmp("from",  how->stptr)) read   = 1;
42         if (!strcmp("error", how->stptr)) except = 1;
43         if (!strcmp("any",   how->stptr)) read = write = except = 1;
44         if (!read && !write && !except) {
45                 printf("select: invalid select type: %.*s\n",
46                                 (int)how->stlen, how->stptr);
47                 return make_number((AWKNUM) -EINVAL);
48         }
49
50         /* - check timeout */
51         int    first = 1;
52         struct timeval _timeout = {.tv_sec = 1, .tv_usec = 0};
53         struct timeval *timeout = &_timeout;
54         NODE *next = get_scalar_argument(1, FALSE);
55         if (next->type == Node_val && next->flags & NUMBER) {
56                 AWKNUM num = force_number(next);
57                 if (num < 0) {
58                         timeout  = NULL;
59                 } else {
60                         _timeout.tv_sec  = (int)num;
61                         _timeout.tv_usec = (num - (int)num) * 1E6;
62                         printf("timeout -> %lf %ld,%ld\n", num,
63                                         _timeout.tv_sec,
64                                         _timeout.tv_usec);
65                 }
66                 first = 2;
67         }
68
69         /* Clear fds */
70         int nfds = 0;
71         fd_set readfds, writefds, exceptfds;
72         FD_ZERO(&readfds);
73         FD_ZERO(&writefds);
74         FD_ZERO(&exceptfds);
75
76         /* Set fds */
77         for (int i = first; i < nargs; i++) {
78                 NODE *node = get_scalar_argument(i, TRUE);
79                 if (node == NULL)
80                         continue;
81                 NODE *str  = force_string(node);
82                 struct redirect *redir =
83                         getredirect(str->stptr, str->stlen);
84                 if (redir == NULL) {
85                         int err = 0;
86                         int type = read && write ? redirect_twoway :
87                                    read          ? redirect_input  :
88                                    write         ? redirect_output : 0 ;
89                         redir = redirect(str, type, &err);
90                 }
91                 if (redir == NULL) {
92                         lintwarn("select: arg %d is not a redirect", i);
93                         continue;
94                 }
95                 if ((read  || except) && redir->iop->fd >= 0) {
96                         int fd = redir->iop->fd;
97                         if (read)      FD_SET(fd, &readfds);
98                         if (except)    FD_SET(fd, &exceptfds);
99                         if (fd > nfds) nfds = fd;
100                 }
101                 if ((write || except) && redir->fp) {
102                         int fd = fileno(redir->fp);
103                         if (write)     FD_SET(fd, &writefds);
104                         if (except)    FD_SET(fd, &exceptfds);
105                         if (fd > nfds) nfds = fd;
106                 }
107         }
108
109         /* Select fds */
110         int rval = select(nfds+1, &readfds, &writefds, &exceptfds, timeout);
111         if (rval == 0)
112                 return make_number((AWKNUM) 0);
113         if (rval == -1)
114                 return make_number((AWKNUM) 0);
115
116         /* Return */
117         for (int i = first; i < nargs; i++) {
118                 NODE *node = get_scalar_argument(i, TRUE);
119                 if (node == NULL)
120                         continue;
121                 NODE *str  = force_string(node);
122                 struct redirect *redir =
123                         getredirect(str->stptr, str->stlen);
124                 if (redir == NULL)
125                         continue;
126                 if ((read  || except) && redir->iop->fd >= 0) {
127                         int fd = redir->iop->fd;
128                         if ((read   && FD_ISSET(fd, &readfds))  ||
129                             (except && FD_ISSET(fd, &writefds)))
130                                 return node;
131                 }
132                 if ((write || except) && redir->fp) {
133                         int fd = fileno(redir->fp);
134                         if ((write  && FD_ISSET(fd, &writefds)) ||
135                             (except && FD_ISSET(fd, &exceptfds)))
136                                 return node;
137                 }
138         }
139
140         /* Error */
141         return make_number((AWKNUM) 0);
142 }
143
144 /* Load select function */
145 NODE *dlload(NODE *tree, void *dl)
146 {
147         make_builtin("select", do_select, 99);
148         return make_number((AWKNUM) 0);
149 }