openenvutils/commandshell/shell/src/modules/zselect.c
changeset 0 2e3d3ce01487
child 4 0fdb7f6b0309
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 // zselect.c - builtin support for select system call
       
     2 //
       
     3 // © Portions copyright (c) 2007 Symbian Software Ltd. All rights reserved.
       
     4 //
       
     5 /*
       
     6  * This file is part of zsh, the Z shell.
       
     7  *
       
     8  * Copyright (c) 1998-2001 Peter Stephenson
       
     9  * All rights reserved.
       
    10  *
       
    11  * Permission is hereby granted, without written agreement and without
       
    12  * license or royalty fees, to use, copy, modify, and distribute this
       
    13  * software and to distribute modified versions of this software for any
       
    14  * purpose, provided that the above copyright notice and the following
       
    15  * two paragraphs appear in all copies of this software.
       
    16  *
       
    17  * In no event shall Peter Stephenson or the Zsh Development
       
    18  * Group be liable to any party for direct, indirect, special, incidental,
       
    19  * or consequential damages arising out of the use of this software and
       
    20  * its documentation, even if Peter Stephenson, and the Zsh
       
    21  * Development Group have been advised of the possibility of such damage.
       
    22  *
       
    23  * Peter Stephenson and the Zsh Development Group specifically
       
    24  * disclaim any warranties, including, but not limited to, the implied
       
    25  * warranties of merchantability and fitness for a particular purpose.  The
       
    26  * software provided hereunder is on an "as is" basis, and Peter Stephenson
       
    27  * and the Zsh Development Group have no obligation to provide maintenance,
       
    28  * support, updates, enhancements, or modifications.
       
    29  *
       
    30  */
       
    31 #include "zselect.mdh"
       
    32 #include "zselect.pro"
       
    33 
       
    34 #ifdef __SYMBIAN32__
       
    35 #ifdef __WINSCW__
       
    36 #pragma warn_unusedarg off
       
    37 #endif//__WINSCW__
       
    38 #endif//__SYMBIAN32__
       
    39 
       
    40 /* Helper functions */
       
    41 
       
    42 /*
       
    43  * Handle an fd by adding it to the current fd_set.
       
    44  * Return 1 for error (after printing a message), 0 for OK.
       
    45  */
       
    46 static int
       
    47 handle_digits(char *nam, char *argptr, fd_set *fdset, int *fdmax)
       
    48 {
       
    49     int fd;
       
    50     char *endptr;
       
    51 
       
    52     if (!isdigit(STOUC(*argptr))) {
       
    53 	zwarnnam(nam, "expecting file descriptor: %s", argptr, 0);
       
    54 	return 1;
       
    55     }
       
    56     fd = (int)zstrtol(argptr, &endptr, 10);
       
    57     if (*endptr) {
       
    58 	zwarnnam(nam, "garbage after file descriptor: %s", endptr, 0);
       
    59 	return 1;
       
    60     }
       
    61 
       
    62     FD_SET(fd, fdset);
       
    63     if (fd+1 > *fdmax)
       
    64 	*fdmax = fd+1;
       
    65     return 0;
       
    66 }
       
    67 
       
    68 /* The builtin itself */
       
    69 
       
    70 /**/
       
    71 static int
       
    72 bin_zselect(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
       
    73 {
       
    74 #ifdef HAVE_SELECT
       
    75     int i, fd, fdsetind = 0, fdmax = 0, fdcount;
       
    76     fd_set fdset[3];
       
    77     const char fdchar[3] = "rwe";
       
    78     struct timeval tv, *tvptr = NULL;
       
    79     char *outarray = "reply", **outdata, **outptr;
       
    80     char *outhash = NULL;
       
    81     LinkList fdlist;
       
    82 
       
    83     for (i = 0; i < 3; i++)
       
    84 	FD_ZERO(fdset+i);
       
    85 
       
    86     for (; *args; args++) {
       
    87 	char *argptr = *args, *endptr;
       
    88 	zlong tempnum;
       
    89 	if (*argptr == '-') {
       
    90 	    for (argptr++; *argptr; argptr++) {
       
    91 		switch (*argptr) {
       
    92 		    /*
       
    93 		     * Array name for reply, if not $reply.
       
    94 		     * This gets set to e.g. `-r 0 -w 1' if 0 is ready
       
    95 		     * for reading and 1 is ready for writing.
       
    96 		     */
       
    97 		case 'a':
       
    98 		case 'A':
       
    99 		    i = *argptr;
       
   100 		    if (argptr[1])
       
   101 			argptr++;
       
   102 		    else if (args[1]) {
       
   103 			argptr = *++args;
       
   104 		    } else {
       
   105 			zwarnnam(nam, "argument expected after -%c", NULL,
       
   106 				 *argptr);
       
   107 			return 1;
       
   108 		    }
       
   109 		    if (idigit(*argptr) || !isident(argptr)) {
       
   110 			zwarnnam(nam, "invalid array name: %s", argptr, 0);
       
   111 			return 1;
       
   112 		    }
       
   113 		    if (i == 'a')
       
   114 			outarray = argptr;
       
   115 		    else
       
   116 			outhash = argptr;
       
   117 		    /* set argptr to next to last char because of increment */
       
   118 		    while (argptr[1])
       
   119 			argptr++;
       
   120 		    break;
       
   121 
       
   122 		    /* Following numbers indicate fd's for reading */
       
   123 		case 'r':
       
   124 		    fdsetind = 0;
       
   125 		    break;
       
   126 
       
   127 		    /* Following numbers indicate fd's for writing */
       
   128 		case 'w':
       
   129 		    fdsetind = 1;
       
   130 		    break;
       
   131 
       
   132 		    /* Following numbers indicate fd's for errors */
       
   133 		case 'e':
       
   134 		    fdsetind = 2;
       
   135 		    break;
       
   136 
       
   137 		    /*
       
   138 		     * Get a timeout value in hundredths of a second
       
   139 		     * (same units as KEYTIMEOUT).  0 means just poll.
       
   140 		     * If not given, blocks indefinitely.
       
   141 		     */
       
   142 		case 't':
       
   143 		    if (argptr[1])
       
   144 			argptr++;
       
   145 		    else if (args[1]) {
       
   146 			argptr = *++args;
       
   147 		    } else {
       
   148 			zwarnnam(nam, "argument expected after -%c", NULL, 
       
   149 				 *argptr);
       
   150 			return 1;
       
   151 		    }
       
   152 		    if (!idigit(*argptr)) {
       
   153 			zwarnnam(nam, "number expected after -t", NULL, 0);
       
   154 			return 1;
       
   155 		    }
       
   156 		    tempnum = zstrtol(argptr, &endptr, 10);
       
   157 		    if (*endptr) {
       
   158 			zwarnnam(nam, "garbage after -t argument: %s",
       
   159 				 endptr, 0);
       
   160 			return 1;
       
   161 		    }
       
   162 		    /* timevalue now active */
       
   163 		    tvptr = &tv;
       
   164 		    tv.tv_sec = (long)(tempnum / 100);
       
   165 		    tv.tv_usec = (long)(tempnum % 100) * 10000L;
       
   166 
       
   167 		    /* remember argptr is incremented at end of loop */
       
   168 		    argptr = endptr - 1;
       
   169 		    break;
       
   170 
       
   171 		    /* Digits following option without arguments are fd's. */
       
   172 		default:
       
   173 		    if (handle_digits(nam, argptr, fdset+fdsetind,
       
   174 				      &fdmax))
       
   175 			return 1;
       
   176 		}
       
   177 	    }
       
   178 	} else if (handle_digits(nam, argptr, fdset+fdsetind, &fdmax))
       
   179 	    return 1;
       
   180     }
       
   181 
       
   182     errno = 0;
       
   183     do {
       
   184 	i = select(fdmax, (SELECT_ARG_2_T)fdset, (SELECT_ARG_2_T)(fdset+1),
       
   185 		   (SELECT_ARG_2_T)(fdset+2), tvptr);
       
   186     } while (i < 0 && errno == EINTR && !errflag);
       
   187 
       
   188     if (i <= 0) {
       
   189 	if (i < 0)
       
   190 	    zwarnnam(nam, "error on select: %e", NULL, errno);
       
   191 	/* else no fd's set.  Presumably a timeout. */
       
   192 	return 1;
       
   193     }
       
   194 
       
   195     /*
       
   196      * Make a linked list of all file descriptors which are ready.
       
   197      * These go into an array preceded by -r, -w or -e for read, write,
       
   198      * error as appropriate.  Typically there will only be one set
       
   199      * so this looks rather like overkill.
       
   200      */
       
   201     fdlist = znewlinklist();
       
   202     for (i = 0; i < 3; i++) {
       
   203 	int doneit = 0;
       
   204 	for (fd = 0; fd < fdmax; fd++) {
       
   205 	    if (FD_ISSET(fd, fdset+i)) {
       
   206 		char buf[BDIGBUFSIZE];
       
   207 		if (outhash) {
       
   208 		    /*
       
   209 		     * Key/value pairs; keys are fd's (as strings),
       
   210 		     * value is a (possibly improper) subset of "rwe".
       
   211 		     */
       
   212 		    LinkNode nptr;
       
   213 		    int found = 0;
       
   214 
       
   215 		    convbase(buf, fd, 10);
       
   216 		    for (nptr = firstnode(fdlist); nptr; 
       
   217 			 nptr = nextnode(nextnode(nptr))) {
       
   218 			if (!strcmp((char *)getdata(nptr), buf)) {
       
   219 			    /* Already there, add new character. */
       
   220 			    void **dataptr = getaddrdata(nextnode(nptr));
       
   221 			    char *data = (char *)*dataptr, *ptr;
       
   222 			    found = 1;
       
   223 			    if (!strchr(data, fdchar[i])) {
       
   224 				strcpy(buf, data);
       
   225 				for (ptr = buf; *ptr; ptr++)
       
   226 				    ;
       
   227 				*ptr++ = fdchar[i];
       
   228 				*ptr = '\0';
       
   229 				zsfree(data);
       
   230 				*dataptr = ztrdup(buf);
       
   231 			    }
       
   232 			    break;
       
   233 			}
       
   234 		    }
       
   235 		    if (!found) {
       
   236 			/* Add new key/value pair. */
       
   237 			zaddlinknode(fdlist, ztrdup(buf));
       
   238 			buf[0] = fdchar[i];
       
   239 			buf[1] = '\0';
       
   240 			zaddlinknode(fdlist, ztrdup(buf));
       
   241 		    }
       
   242 		} else {
       
   243 		    /* List of fd's preceded by -r, -w, -e. */
       
   244 		    if (!doneit) {
       
   245 			buf[0] = '-';
       
   246 			buf[1] = fdchar[i];
       
   247 			buf[2] = 0;
       
   248 			zaddlinknode(fdlist, ztrdup(buf));
       
   249 			doneit = 1;
       
   250 		    }
       
   251 		    convbase(buf, fd, 10);
       
   252 		    zaddlinknode(fdlist, ztrdup(buf));
       
   253 		}
       
   254 	    }
       
   255 	}
       
   256     }
       
   257 
       
   258     /* convert list to array */
       
   259     fdcount = countlinknodes(fdlist);
       
   260     outptr = outdata = (char **)zalloc((fdcount+1)*sizeof(char *));
       
   261     while (nonempty(fdlist))
       
   262 	*outptr++ = getlinknode(fdlist);
       
   263     *outptr = '\0';
       
   264     /* and store in array parameter */
       
   265     if (outhash)
       
   266 	sethparam(outhash, outdata);
       
   267     else
       
   268 	setaparam(outarray, outdata);
       
   269     freelinklist(fdlist, NULL);
       
   270 
       
   271     return 0;
       
   272 #else
       
   273     /* TODO: use poll */
       
   274     zerrnam(nam, "your system does not implement the select system call.",
       
   275 	    NULL, 0);
       
   276     return 2;
       
   277 #endif
       
   278 }
       
   279 
       
   280 static struct builtin bintab[] = {
       
   281     BUILTIN("zselect", 0, bin_zselect, 0, -1, 0, NULL, NULL),
       
   282 };
       
   283 
       
   284 /* The load/unload routines required by the zsh library interface */
       
   285 
       
   286 /**/
       
   287 int
       
   288 setup_(UNUSED(Module m))
       
   289 {
       
   290     return 0;
       
   291 }
       
   292 
       
   293 /**/
       
   294 int
       
   295 boot_(Module m)
       
   296 {
       
   297     return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
       
   298 }
       
   299 
       
   300 
       
   301 /**/
       
   302 int
       
   303 cleanup_(UNUSED(Module m))
       
   304 {
       
   305     deletebuiltins("zselect", bintab, sizeof(bintab)/sizeof(*bintab));
       
   306     return 0;
       
   307 }
       
   308 
       
   309 /**/
       
   310 int
       
   311 finish_(UNUSED(Module m))
       
   312 {
       
   313     return 0;
       
   314 }