static int bin_vared(char *name, char **args, Options ops, UNUSED(int func)) { char *s, *t, *ova = varedarg; struct value vbuf; Value v; Param pm = 0; int ifl; int type = PM_SCALAR, obreaks = breaks, haso = 0, oSHTTY = 0; char *p1, *p2, *main_keymapname, *vicmd_keymapname, *init, *finish; Keymap main_keymapsave = NULL, vicmd_keymapsave = NULL; FILE *oshout = NULL; if ((interact && unset(USEZLE)) || !strcmp(term, "emacs")) { zwarnnam(name, "ZLE not enabled"); return 1; } if (zleactive) { zwarnnam(name, "ZLE cannot be used recursively (yet)"); return 1; } if (OPT_ISSET(ops,'A')) { if (OPT_ISSET(ops, 'a')) { zwarnnam(name, "specify only one of -a and -A"); return 1; } type = PM_HASHED; } else if (OPT_ISSET(ops,'a')) type = PM_ARRAY; p1 = OPT_ARG_SAFE(ops,'p'); p2 = OPT_ARG_SAFE(ops,'r'); main_keymapname = OPT_ARG_SAFE(ops,'M'); vicmd_keymapname = OPT_ARG_SAFE(ops,'m'); init = OPT_ARG_SAFE(ops,'i'); finish = OPT_ARG_SAFE(ops,'f'); if (type != PM_SCALAR && !OPT_ISSET(ops,'c')) { zwarnnam(name, "-%s ignored", type == PM_ARRAY ? "a" : "A"); } /* handle non-existent parameter */ s = args[0]; queue_signals(); v = fetchvalue(&vbuf, &s, (!OPT_ISSET(ops,'c') || type == PM_SCALAR), SCANPM_WANTKEYS|SCANPM_WANTVALS|SCANPM_MATCHMANY); if (!v && !OPT_ISSET(ops,'c')) { unqueue_signals(); zwarnnam(name, "no such variable: %s", args[0]); return 1; } else if (v) { if (*s) { zwarnnam(name, "not an identifier: `%s'", args[0]); return 1; } if (v->isarr) { /* Array: check for separators and quote them. */ char **arr = getarrvalue(v), **aptr, **tmparr, **tptr; tptr = tmparr = (char **)zhalloc(sizeof(char *)*(arrlen(arr)+1)); for (aptr = arr; *aptr; aptr++) { int sepcount = 0, clen; convchar_t c; /* * See if this word contains a separator character * or backslash */ MB_METACHARINIT(); for (t = *aptr; *t; ) { if (*t == '\\') { t++; sepcount++; } else { t += MB_METACHARLENCONV(t, &c); if (WC_ZISTYPE(c, ISEP)) sepcount++; } } if (sepcount) { /* Yes, so allocate enough space to quote it. */ char *newstr, *nptr; newstr = zhalloc(strlen(*aptr)+sepcount+1); /* Go through string quoting separators */ MB_METACHARINIT(); for (t = *aptr, nptr = newstr; *t; ) { if (*t == '\\') { *nptr++ = '\\'; *nptr++ = *t++; } else { clen = MB_METACHARLENCONV(t, &c); if (WC_ZISTYPE(c, ISEP)) *nptr++ = '\\'; while (clen--) *nptr++ = *t++; } } *nptr = '\0'; /* Stick this into the array of words to join up */ *tptr++ = newstr; } else *tptr++ = *aptr; /* No, keep original array element */ } *tptr = NULL; s = sepjoin(tmparr, NULL, 0); } else { s = ztrdup(getstrvalue(v)); } unqueue_signals(); } else if (*s) { unqueue_signals(); zwarnnam(name, "invalid parameter name: %s", args[0]); return 1; } else { unqueue_signals(); s = ztrdup(s); } if (SHTTY == -1 || OPT_ISSET(ops,'t')) { /* need to open /dev/tty specially */ oSHTTY = SHTTY; if ((SHTTY = open(OPT_ISSET(ops,'t') ? OPT_ARG(ops,'t') : "/dev/tty", O_RDWR|O_NOCTTY)) == -1) { zwarnnam(name, "can't access terminal"); zsfree(s); return 1; } if (!isatty(SHTTY)) { zwarnnam(name, "%s: not a terminal", OPT_ARG(ops,'t')); close(SHTTY); SHTTY = oSHTTY; zsfree(s); return 1; } oshout = shout; init_shout(); haso = 1; } /* edit the parameter value */ zpushnode(bufstack, s); if (main_keymapname && savekeymap(name, "main", main_keymapname, &main_keymapsave)) main_keymapname = NULL; if (vicmd_keymapname && savekeymap(name, "vicmd", vicmd_keymapname, &vicmd_keymapsave)) vicmd_keymapname = NULL; varedarg = *args; ifl = isfirstln; if (OPT_ISSET(ops,'h')) hbegin(2); isfirstln = OPT_ISSET(ops,'e'); t = zleread(&p1, &p2, OPT_ISSET(ops,'h') ? ZLRF_HISTORY : 0, ZLCON_VARED, init ? init : "zle-line-init", finish ? finish : "zle-line-finish"); if (OPT_ISSET(ops,'h')) hend(NULL); isfirstln = ifl; varedarg = ova; restorekeymap(name, "main", main_keymapname, main_keymapsave); restorekeymap(name, "vicmd", vicmd_keymapname, vicmd_keymapsave); if (haso) { fclose(shout); /* close(SHTTY) */ shout = oshout; SHTTY = oSHTTY; } if (!t || errflag) { /* error in editing */ errflag &= ~ERRFLAG_ERROR; breaks = obreaks; if (t) zsfree(t); return 1; } /* strip off trailing newline, if any */ if (t[strlen(t) - 1] == '\n') t[strlen(t) - 1] = '\0'; /* final assignment of parameter value */ if (OPT_ISSET(ops,'c')) { unsetparam(args[0]); createparam(args[0], type); } queue_signals(); pm = (Param) paramtab->getnode(paramtab, args[0]); if (pm && (PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED))) { char **a; /* * Use spacesplit with fourth argument 1: identify quoted separators, * and unquote. This duplicates the string, so we still need to free. */ a = spacesplit(t, 1, 0, 1); zsfree(t); if (PM_TYPE(pm->node.flags) == PM_ARRAY) setaparam(args[0], a); else sethparam(args[0], a); } else setsparam(args[0], t); unqueue_signals(); return 0; }
static int bin_zselect(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) { #ifdef HAVE_SELECT int i, fd, fdsetind = 0, fdmax = 0, fdcount; fd_set fdset[3]; const char fdchar[3] = "rwe"; struct timeval tv, *tvptr = NULL; char *outarray = "reply", **outdata, **outptr; char *outhash = NULL; LinkList fdlist; for (i = 0; i < 3; i++) FD_ZERO(fdset+i); for (; *args; args++) { char *argptr = *args, *endptr; zlong tempnum; if (*argptr == '-') { for (argptr++; *argptr; argptr++) { switch (*argptr) { /* * Array name for reply, if not $reply. * This gets set to e.g. `-r 0 -w 1' if 0 is ready * for reading and 1 is ready for writing. */ case 'a': case 'A': i = *argptr; if (argptr[1]) argptr++; else if (args[1]) { argptr = *++args; } else { zwarnnam(nam, "argument expected after -%c", *argptr); return 1; } if (idigit(*argptr) || !isident(argptr)) { zwarnnam(nam, "invalid array name: %s", argptr); return 1; } if (i == 'a') outarray = argptr; else outhash = argptr; /* set argptr to next to last char because of increment */ while (argptr[1]) argptr++; break; /* Following numbers indicate fd's for reading */ case 'r': fdsetind = 0; break; /* Following numbers indicate fd's for writing */ case 'w': fdsetind = 1; break; /* Following numbers indicate fd's for errors */ case 'e': fdsetind = 2; break; /* * Get a timeout value in hundredths of a second * (same units as KEYTIMEOUT). 0 means just poll. * If not given, blocks indefinitely. */ case 't': if (argptr[1]) argptr++; else if (args[1]) { argptr = *++args; } else { zwarnnam(nam, "argument expected after -%c", *argptr); return 1; } if (!idigit(*argptr)) { zwarnnam(nam, "number expected after -t"); return 1; } tempnum = zstrtol(argptr, &endptr, 10); if (*endptr) { zwarnnam(nam, "garbage after -t argument: %s", endptr); return 1; } /* timevalue now active */ tvptr = &tv; tv.tv_sec = (long)(tempnum / 100); tv.tv_usec = (long)(tempnum % 100) * 10000L; /* remember argptr is incremented at end of loop */ argptr = endptr - 1; break; /* Digits following option without arguments are fd's. */ default: if (handle_digits(nam, argptr, fdset+fdsetind, &fdmax)) return 1; } } } else if (handle_digits(nam, argptr, fdset+fdsetind, &fdmax)) return 1; } errno = 0; do { i = select(fdmax, (SELECT_ARG_2_T)fdset, (SELECT_ARG_2_T)(fdset+1), (SELECT_ARG_2_T)(fdset+2), tvptr); } while (i < 0 && errno == EINTR && !errflag); if (i <= 0) { if (i < 0) zwarnnam(nam, "error on select: %e", errno); /* else no fd's set. Presumably a timeout. */ return 1; } /* * Make a linked list of all file descriptors which are ready. * These go into an array preceded by -r, -w or -e for read, write, * error as appropriate. Typically there will only be one set * so this looks rather like overkill. */ fdlist = znewlinklist(); for (i = 0; i < 3; i++) { int doneit = 0; for (fd = 0; fd < fdmax; fd++) { if (FD_ISSET(fd, fdset+i)) { char buf[BDIGBUFSIZE]; if (outhash) { /* * Key/value pairs; keys are fd's (as strings), * value is a (possibly improper) subset of "rwe". */ LinkNode nptr; int found = 0; convbase(buf, fd, 10); for (nptr = firstnode(fdlist); nptr; nptr = nextnode(nextnode(nptr))) { if (!strcmp((char *)getdata(nptr), buf)) { /* Already there, add new character. */ void **dataptr = getaddrdata(nextnode(nptr)); char *data = (char *)*dataptr, *ptr; found = 1; if (!strchr(data, fdchar[i])) { strcpy(buf, data); for (ptr = buf; *ptr; ptr++) ; *ptr++ = fdchar[i]; *ptr = '\0'; zsfree(data); *dataptr = ztrdup(buf); } break; } } if (!found) { /* Add new key/value pair. */ zaddlinknode(fdlist, ztrdup(buf)); buf[0] = fdchar[i]; buf[1] = '\0'; zaddlinknode(fdlist, ztrdup(buf)); } } else { /* List of fd's preceded by -r, -w, -e. */ if (!doneit) { buf[0] = '-'; buf[1] = fdchar[i]; buf[2] = 0; zaddlinknode(fdlist, ztrdup(buf)); doneit = 1; } convbase(buf, fd, 10); zaddlinknode(fdlist, ztrdup(buf)); } } } } /* convert list to array */ fdcount = countlinknodes(fdlist); outptr = outdata = (char **)zalloc((fdcount+1)*sizeof(char *)); while (nonempty(fdlist)) *outptr++ = getlinknode(fdlist); *outptr = NULL; /* and store in array parameter */ if (outhash) sethparam(outhash, outdata); else setaparam(outarray, outdata); freelinklist(fdlist, NULL); return 0; #else /* TODO: use poll */ zerrnam(nam, "your system does not implement the select system call."); return 2; #endif }
static int bin_stat(char *name, char **args, Options ops, UNUSED(int func)) { char **aptr, *arrnam = NULL, **array = NULL, **arrptr = NULL; char *hashnam = NULL, **hash = NULL, **hashptr = NULL; int len, iwhich = -1, ret = 0, flags = 0, arrsize = 0, fd = 0; struct stat statbuf; int found = 0, nargs; timefmt = "%a %b %e %k:%M:%S %Z %Y"; for (; *args && (**args == '+' || **args == '-'); args++) { char *arg = *args+1; if (!*arg || *arg == '-' || *arg == '+') { args++; break; } if (**args == '+') { if (found) break; len = strlen(arg); for (aptr = statelts; *aptr; aptr++) if (!strncmp(*aptr, arg, len)) { found++; iwhich = aptr - statelts; } if (found > 1) { zwarnnam(name, "%s: ambiguous stat element", arg); return 1; } else if (found == 0) { zwarnnam(name, "%s: no such stat element", arg); return 1; } /* if name of link requested, turn on lstat */ if (iwhich == ST_READLINK) ops->ind['L'] = 1; flags |= STF_PICK; } else { for (; *arg; arg++) { if (strchr("glLnNorstT", *arg)) ops->ind[STOUC(*arg)] = 1; else if (*arg == 'A') { if (arg[1]) { arrnam = arg+1; } else if (!(arrnam = *++args)) { zwarnnam(name, "missing parameter name"); return 1; } flags |= STF_ARRAY; break; } else if (*arg == 'H') { if (arg[1]) { hashnam = arg+1; } else if (!(hashnam = *++args)) { zwarnnam(name, "missing parameter name"); return 1; } flags |= STF_HASH; break; } else if (*arg == 'f') { char *sfd; ops->ind['f'] = 1; if (arg[1]) { sfd = arg+1; } else if (!(sfd = *++args)) { zwarnnam(name, "missing file descriptor"); return 1; } fd = zstrtol(sfd, &sfd, 10); if (*sfd) { zwarnnam(name, "bad file descriptor"); return 1; } break; } else if (*arg == 'F') { if (arg[1]) { timefmt = arg+1; } else if (!(timefmt = *++args)) { zwarnnam(name, "missing time format"); return 1; } /* force string format in order to use time format */ ops->ind['s'] = 1; break; } else { zwarnnam(name, "bad option: -%c", *arg); return 1; } } } } if ((flags & STF_ARRAY) && (flags & STF_HASH)) { /* We don't implement setting multiple variables at once */ zwarnnam(name, "both array and hash requested"); return 1; /* Alternate method would be to make -H blank arrnam etc etc * * and so get 'silent loss' of earlier choice, which would * * be similar to stat -A foo -A bar filename */ } if (OPT_ISSET(ops,'l')) { /* list types and return: can also list to array */ if (arrnam) { arrptr = array = (char **)zalloc((ST_COUNT+1)*sizeof(char *)); array[ST_COUNT] = NULL; } for (aptr = statelts; *aptr; aptr++) { if (arrnam) { *arrptr++ = ztrdup(*aptr); } else { printf("%s", *aptr); if (aptr[1]) putchar(' '); } } if (arrnam) { setaparam(arrnam, array); if (errflag) return 1; } else putchar('\n'); return 0; } if (!*args && !OPT_ISSET(ops,'f')) { zwarnnam(name, "no files given"); return 1; } else if (*args && OPT_ISSET(ops,'f')) { zwarnnam(name, "no files allowed with -f"); return 1; } nargs = 0; if (OPT_ISSET(ops,'f')) nargs = 1; else for (aptr = args; *aptr; aptr++) nargs++; if (OPT_ISSET(ops,'g')) { flags |= STF_GMT; ops->ind['s'] = 1; } if (OPT_ISSET(ops,'s') || OPT_ISSET(ops,'r')) flags |= STF_STRING; if (OPT_ISSET(ops,'r') || !OPT_ISSET(ops,'s')) flags |= STF_RAW; if (OPT_ISSET(ops,'n')) flags |= STF_FILE; if (OPT_ISSET(ops,'o')) flags |= STF_OCTAL; if (OPT_ISSET(ops,'t')) flags |= STF_NAME; if (!(arrnam || hashnam)) { if (nargs > 1) flags |= STF_FILE; if (!(flags & STF_PICK)) flags |= STF_NAME; } if (OPT_ISSET(ops,'N') || OPT_ISSET(ops,'f')) flags &= ~STF_FILE; if (OPT_ISSET(ops,'T') || OPT_ISSET(ops,'H')) flags &= ~STF_NAME; if (hashnam) { if (nargs > 1) { zwarnnam(name, "only one file allowed with -H"); return 1; } arrsize = (flags & STF_PICK) ? 1 : ST_COUNT; if (flags & STF_FILE) arrsize++; hashptr = hash = (char **)zshcalloc((arrsize+1)*2*sizeof(char *)); } if (arrnam) { arrsize = (flags & STF_PICK) ? 1 : ST_COUNT; if (flags & STF_FILE) arrsize++; arrsize *= nargs; arrptr = array = (char **)zshcalloc((arrsize+1)*sizeof(char *)); } for (; OPT_ISSET(ops,'f') || *args; args++) { char outbuf[PATH_MAX + 9]; /* "link " + link name + NULL */ int rval = OPT_ISSET(ops,'f') ? fstat(fd, &statbuf) : OPT_ISSET(ops,'L') ? lstat(unmeta(*args), &statbuf) : stat(unmeta(*args), &statbuf); if (rval) { if (OPT_ISSET(ops,'f')) sprintf(outbuf, "%d", fd); zwarnnam(name, "%s: %e", OPT_ISSET(ops,'f') ? outbuf : *args, errno); ret = 1; if (OPT_ISSET(ops,'f') || arrnam) break; else continue; } if (flags & STF_FILE) { if (arrnam) *arrptr++ = ztrdup(*args); else if (hashnam) { *hashptr++ = ztrdup(HNAMEKEY); *hashptr++ = ztrdup(*args); } else printf("%s%s", *args, (flags & STF_PICK) ? " " : ":\n"); } if (iwhich > -1) { statprint(&statbuf, outbuf, *args, iwhich, flags); if (arrnam) *arrptr++ = metafy(outbuf, -1, META_DUP); else if (hashnam) { /* STF_NAME explicitly turned off for ops.ind['H'] above */ *hashptr++ = ztrdup(statelts[iwhich]); *hashptr++ = metafy(outbuf, -1, META_DUP); } else printf("%s\n", outbuf); } else { int i; for (i = 0; i < ST_COUNT; i++) { statprint(&statbuf, outbuf, *args, i, flags); if (arrnam) *arrptr++= metafy(outbuf, -1, META_DUP); else if (hashnam) { /* STF_NAME explicitly turned off for ops.ind['H'] above */ *hashptr++ = ztrdup(statelts[i]); *hashptr++ = metafy(outbuf, -1, META_DUP); } else printf("%s\n", outbuf); } } if (OPT_ISSET(ops,'f')) break; if (!arrnam && !hashnam && args[1] && !(flags & STF_PICK)) putchar('\n'); } if (arrnam) { if (ret) freearray(array); else { setaparam(arrnam, array); if (errflag) return 1; } } if (hashnam) { if (ret) freearray(hash); else { sethparam(hashnam, hash); if (errflag) return 1; } } return ret; }