static int bin_getattr(char *nam, char **argv, Options ops, UNUSED(int func)) { int ret = 0; int val_len = 0, attr_len = 0, slen; char *value, *file = argv[0], *attr = argv[1], *param = argv[2]; int symlink = OPT_ISSET(ops, 'h'); unmetafy(file, &slen); unmetafy(attr, NULL); val_len = xgetxattr(file, attr, NULL, 0, symlink); if (val_len == 0) { if (param) unsetparam(param); return 0; } if (val_len > 0) { value = (char *)zalloc(val_len+1); attr_len = xgetxattr(file, attr, value, val_len, symlink); if (attr_len > 0 && attr_len <= val_len) { value[attr_len] = '\0'; if (param) setsparam(param, metafy(value, attr_len, META_DUP)); else printf("%s\n", value); } zfree(value, val_len+1); } if (val_len < 0 || attr_len < 0 || attr_len > val_len) { zwarnnam(nam, "%s: %e", metafy(file, slen, META_NOALLOC), errno); ret = 1 + ((val_len > 0 && attr_len > val_len) || attr_len < 0); } return ret; }
static void setpmmapfile(Param pm, char *value) { int fd = -1, len; char *name = ztrdup(pm->nam); #ifdef USE_MMAP caddr_t mmptr; #else FILE *fout; #endif /* * First unmetafy the value, and the name since we don't * where it's been. */ unmetafy(name, &len); unmetafy(value, &len); /* Open the file for writing */ #ifdef USE_MMAP if (!(pm->flags & PM_READONLY) && (fd = open(name, O_RDWR|O_CREAT|O_NOCTTY, 0666)) >= 0 && (mmptr = (caddr_t)mmap((caddr_t)0, len, PROT_READ | PROT_WRITE, MMAP_ARGS, fd, (off_t)0)) != (caddr_t)-1) { /* * First we need to make sure the file is long enough for * when we msync. On AIX, at least, we just get zeroes otherwise. */ ftruncate(fd, len); memcpy(mmptr, value, len); #ifndef MS_SYNC #define MS_SYNC 0 #endif msync(mmptr, len, MS_SYNC); /* * Then we need to truncate again, since mmap() always maps complete * pages. Honestly, I tried it without, and you need both. */ ftruncate(fd, len); munmap(mmptr, len); } #else /* don't USE_MMAP */ /* can't be bothered to do anything too clever here */ if ((fout = fopen(name, "w"))) { while (len--) putc(*value++, fout); fclose(fout); } #endif /* USE_MMAP */ if (fd >= 0) close(fd); free(name); free(value); }
static int ptywrite(Ptycmd cmd, char **args, int nonl) { if (*args) { char sp = ' ', *tmp; int len; while (*args) { unmetafy((tmp = dupstring(*args)), &len); if (ptywritestr(cmd, tmp, len) || (*++args && ptywritestr(cmd, &sp, 1))) return 1; } if (!nonl) { sp = '\n'; if (ptywritestr(cmd, &sp, 1)) return 1; } } else { int n; char buf[BUFSIZ]; while ((n = read(0, buf, BUFSIZ)) > 0) if (ptywritestr(cmd, buf, n)) return 1; } return 0; }
static int bin_setattr(char *nam, char **argv, Options ops, UNUSED(int func)) { int ret = 0, slen, vlen; int symlink = OPT_ISSET(ops, 'h'); char *file = argv[0], *attr = argv[1], *value = argv[2]; unmetafy(file, &slen); unmetafy(attr, NULL); unmetafy(value, &vlen); if (xsetxattr(file, attr, value, vlen, 0, symlink)) { zwarnnam(nam, "%s: %e", metafy(file, slen, META_NOALLOC), errno); ret = 1; } return ret; }
static HashNode getlanginfo(UNUSED(HashTable ht), const char *name) { int len, *elem; char *listr, *nameu; Param pm = NULL; nameu = dupstring(name); unmetafy(nameu, &len); pm = (Param) hcalloc(sizeof(struct param)); pm->node.nam = nameu; pm->node.flags = PM_READONLY | PM_SCALAR; pm->gsu.s = &nullsetscalar_gsu; if(name) elem = liitem(name); else elem = NULL; if (elem && (listr = nl_langinfo(*elem))) { pm->u.str = dupstring(listr); } else { /* zwarn("no such lang info: %s", name); */ pm->u.str = dupstring(""); pm->node.flags |= PM_UNSET; } return &pm->node; }
static int bin_cap(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func)) { int ret = 0; cap_t caps; if(*argv) { unmetafy(*argv, NULL); caps = cap_from_text(*argv); if(!caps) { zwarnnam(nam, "invalid capability string"); return 1; } if(cap_set_proc(caps)) { zwarnnam(nam, "can't change capabilities: %e", errno); ret = 1; } } else { char *result = NULL; ssize_t length; caps = cap_get_proc(); if(caps) result = cap_to_text(caps, &length); if(!caps || !result) { zwarnnam(nam, "can't get capabilities: %e", errno); ret = 1; } else puts(result); } cap_free(caps); return ret; }
static int bin_delattr(char *nam, char **argv, Options ops, UNUSED(int func)) { int ret = 0, slen; int symlink = OPT_ISSET(ops, 'h'); char *file = argv[0], **attr = argv; unmetafy(file, &slen); while (*++attr) { unmetafy(*attr, NULL); if (xremovexattr(file, *attr, symlink)) { zwarnnam(nam, "%s: %e", metafy(file, slen, META_NOALLOC), errno); ret = 1; break; } } return ret; }
void setline(char const *s) { sizeline(strlen(s)); strcpy((char *) line, s); unmetafy((char *) line, &ll); if ((cs = ll) && bindtab == altbindtab) cs--; clearlist = 1; }
static HashNode gettermcap(UNUSED(HashTable ht), char *name) { int len, num; char *tcstr, buf[2048], *u; Param pm = NULL; /* This depends on the termcap stuff in init.c */ if (termflags & TERM_BAD) return NULL; if ((termflags & TERM_UNKNOWN) && (isset(INTERACTIVE) || !init_term())) return NULL; unmetafy(name, &len); pm = (Param) hcalloc(sizeof(struct param)); pm->nam = dupstring(name); pm->flags = PM_READONLY; u = buf; /* logic in the following cascade copied from echotc, above */ if ((num = tgetnum(name)) != -1) { pm->gsu.i = &nullsetinteger_gsu; pm->u.val = num; pm->flags |= PM_INTEGER; return (HashNode) pm; } pm->gsu.s = &nullsetscalar_gsu; switch (ztgetflag(name)) { case -1: break; case 0: pm->u.str = dupstring("no"); pm->flags |= PM_SCALAR; return (HashNode) pm; default: pm->u.str = dupstring("yes"); pm->flags |= PM_SCALAR; return (HashNode) pm; } if ((tcstr = (char*)tgetstr(name, &u)) != NULL && tcstr != (char *)-1) { pm->u.str = dupstring(tcstr); pm->flags |= PM_SCALAR; } else { /* zwarn("no such capability: %s", name, 0); */ pm->u.str = dupstring(""); pm->flags |= PM_UNSET; } return (HashNode) pm; }
static int bin_listattr(char *nam, char **argv, Options ops, UNUSED(int func)) { int ret = 0; int val_len, list_len = 0, slen; char *value, *file = argv[0], *param = argv[1]; int symlink = OPT_ISSET(ops, 'h'); unmetafy(file, &slen); val_len = xlistxattr(file, NULL, 0, symlink); if (val_len == 0) { if (param) unsetparam(param); return 0; } if (val_len > 0) { value = (char *)zalloc(val_len+1); list_len = xlistxattr(file, value, val_len, symlink); if (list_len > 0 && list_len <= val_len) { char *p = value; if (param) { if (strlen(value) + 1 == list_len) setsparam(param, metafy(value, list_len-1, META_DUP)); else { int arrlen = 0; char **array = NULL, **arrptr = NULL; while (p < &value[list_len]) { arrlen++; p += strlen(p) + 1; } arrptr = array = (char **)zshcalloc((arrlen+1) * sizeof(char *)); p = value; while (p < &value[list_len]) { *arrptr++ = metafy(p, -1, META_DUP); p += strlen(p) + 1; } setaparam(param, array); } } else while (p < &value[list_len]) { printf("%s\n", p); p += strlen(p) + 1; } } zfree(value, val_len+1); } if (val_len < 0 || list_len < 0 || list_len > val_len) { zwarnnam(nam, "%s: %e", metafy(file, slen, META_NOALLOC), errno); ret = 1 + (list_len > val_len || list_len < 0); } return ret; }
static void unsetpmmapfile(Param pm, UNUSED(int exp)) { /* Unlink the file given by pm->nam */ char *fname = ztrdup(pm->nam); int dummy; unmetafy(fname, &dummy); if (!(pm->flags & PM_READONLY)) unlink(fname); free(fname); }
static int bin_setcap(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func)) { cap_t caps; int ret = 0; unmetafy(*argv, NULL); caps = cap_from_text(*argv++); if(!caps) { zwarnnam(nam, "invalid capability string"); return 1; } do { if(cap_set_file(unmetafy(dupstring(*argv), NULL), caps)) { zwarnnam(nam, "%s: %e", *argv, errno); ret = 1; } } while(*++argv); cap_free(caps); return ret; }
static HashNode getgdbmnode(HashTable ht, const char *name) { int len; char *nameu; Param pm = NULL; nameu = dupstring(name); unmetafy(nameu, &len); pm = (Param) hcalloc(sizeof(struct param)); pm->node.nam = nameu; pm->node.flags = PM_SCALAR; pm->gsu.s = &gdbm_gsu; pm->u.hash = ht; return &pm->node; }
void getline(void) { char *s = (char *)getlinknode(bufstack); if (!s) feep(); else { int cc; unmetafy(s, &cc); spaceinline(cc); memcpy((char *)line + cs, s, cc); cs += cc; free(s); clearlist = 1; } }
static char * get_contents(char *fname) { int fd; #ifdef USE_MMAP caddr_t mmptr; struct stat sbuf; #endif char *val; unmetafy(fname = ztrdup(fname), &fd); #ifdef USE_MMAP if ((fd = open(fname, O_RDONLY | O_NOCTTY)) < 0 || fstat(fd, &sbuf) || (mmptr = (caddr_t)mmap((caddr_t)0, sbuf.st_size, PROT_READ, MMAP_ARGS, fd, (off_t)0)) == (caddr_t)-1) { if (fd >= 0) close(fd); free(fname); return NULL; } /* * Sadly, we need to copy the thing even if metafying doesn't * change it. We just don't know when we might get a chance to * munmap it, otherwise. */ val = metafy((char *)mmptr, sbuf.st_size, META_HEAPDUP); munmap(mmptr, sbuf.st_size); close(fd); #else /* don't USE_MMAP */ val = NULL; if ((fd = open(fname, O_RDONLY | O_NOCTTY)) >= 0) { LinkList ll; if ((ll = readoutput(fd, 1))) val = peekfirst(ll); } #endif /* USE_MMAP */ free(fname); return val; }
static int bin_syswrite(char *nam, char **args, Options ops, UNUSED(int func)) { int outfd = 1, len, count, totcount; char *countvar = NULL; /* -o: output file descriptor if not stdout */ if (OPT_ISSET(ops, 'o')) { outfd = getposint(OPT_ARG(ops, 'o'), nam); if (outfd < 0) return 1; } /* -c: variable in which to store count of bytes written */ if (OPT_ISSET(ops, 'c')) { countvar = OPT_ARG(ops, 'c'); if (!isident(countvar)) { zwarnnam(nam, "not an identifier: %s", countvar); return 1; } } totcount = 0; unmetafy(*args, &len); while (len) { while ((count = write(outfd, *args, len)) < 0) { if (errno != EINTR || errflag || retflag || breaks || contflag) { if (countvar) setiparam(countvar, totcount); return 2; } } *args += count; totcount += count; len -= count; } if (countvar) setiparam(countvar, totcount); return 0; }
static HashNode getterminfo(UNUSED(HashTable ht), const char *name) { int len, num; char *tistr, *nameu; Param pm = NULL; /* This depends on the termcap stuff in init.c */ if (termflags & TERM_BAD) return NULL; if ((termflags & TERM_UNKNOWN) && (isset(INTERACTIVE) || !init_term())) return NULL; nameu = dupstring(name); unmetafy(nameu, &len); pm = (Param) hcalloc(sizeof(struct param)); pm->node.nam = nameu; pm->node.flags = PM_READONLY; if (((num = tigetnum(nameu)) != -1) && (num != -2)) { pm->u.val = num; pm->node.flags |= PM_INTEGER; pm->gsu.i = &nullsetinteger_gsu; } else if ((num = tigetflag(nameu)) != -1) { pm->u.str = num ? dupstring("yes") : dupstring("no"); pm->node.flags |= PM_SCALAR; pm->gsu.s = &nullsetscalar_gsu; } else if ((tistr = (char *)tigetstr(nameu)) != NULL && tistr != (char *)-1) { pm->u.str = dupstring(tistr); pm->node.flags |= PM_SCALAR; pm->gsu.s = &nullsetscalar_gsu; } else { /* zwarn("no such capability: %s", name); */ pm->u.str = dupstring(""); pm->node.flags |= PM_UNSET; pm->gsu.s = &nullsetscalar_gsu; } return &pm->node; }
static int bin_getcap(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func)) { int ret = 0; do { char *result = NULL; ssize_t length; cap_t caps; caps = cap_get_file(unmetafy(dupstring(*argv), NULL)); if(caps) result = cap_to_text(caps, &length); if (!caps || !result) { zwarnnam(nam, "%s: %e", *argv, errno); ret = 1; } else printf("%s %s\n", *argv, result); cap_free(caps); } while(*++argv); return ret; }
static int bin_pcre_compile(char *nam, char **args, Options ops, UNUSED(int func)) { int pcre_opts = 0, pcre_errptr; const char *pcre_error; char *target; if(OPT_ISSET(ops,'a')) pcre_opts |= PCRE_ANCHORED; if(OPT_ISSET(ops,'i')) pcre_opts |= PCRE_CASELESS; if(OPT_ISSET(ops,'m')) pcre_opts |= PCRE_MULTILINE; if(OPT_ISSET(ops,'x')) pcre_opts |= PCRE_EXTENDED; if(OPT_ISSET(ops,'s')) pcre_opts |= PCRE_DOTALL; if (zpcre_utf8_enabled()) pcre_opts |= PCRE_UTF8; pcre_hints = NULL; /* Is this necessary? */ if (pcre_pattern) pcre_free(pcre_pattern); target = ztrdup(*args); unmetafy(target, NULL); pcre_pattern = pcre_compile(target, pcre_opts, &pcre_error, &pcre_errptr, NULL); free(target); if (pcre_pattern == NULL) { zwarnnam(nam, "error in regex: %s", pcre_error); return 1; } return 0; }
static int cond_pcre_match(char **a, int id) { pcre *pcre_pat; const char *pcre_err; char *lhstr, *rhre, *lhstr_plain, *rhre_plain, *avar=NULL; int r = 0, pcre_opts = 0, pcre_errptr, capcnt, *ov, ovsize; int return_value = 0; if (zpcre_utf8_enabled()) pcre_opts |= PCRE_UTF8; lhstr = cond_str(a,0,0); rhre = cond_str(a,1,0); lhstr_plain = ztrdup(lhstr); rhre_plain = ztrdup(rhre); unmetafy(lhstr_plain, NULL); unmetafy(rhre_plain, NULL); pcre_pat = NULL; ov = NULL; ovsize = 0; if (isset(BASHREMATCH)) avar="BASH_REMATCH"; switch(id) { case CPCRE_PLAIN: pcre_pat = pcre_compile(rhre_plain, pcre_opts, &pcre_err, &pcre_errptr, NULL); if (pcre_pat == NULL) { zwarn("failed to compile regexp /%s/: %s", rhre, pcre_err); break; } pcre_fullinfo(pcre_pat, NULL, PCRE_INFO_CAPTURECOUNT, &capcnt); ovsize = (capcnt+1)*3; ov = zalloc(ovsize*sizeof(int)); r = pcre_exec(pcre_pat, NULL, lhstr_plain, strlen(lhstr_plain), 0, 0, ov, ovsize); /* r < 0 => error; r==0 match but not enough size in ov * r > 0 => (r-1) substrings found; r==1 => no substrings */ if (r==0) { zwarn("reportable zsh problem: pcre_exec() returned 0"); return_value = 1; break; } else if (r==PCRE_ERROR_NOMATCH) { return_value = 0; /* no match */ break; } else if (r<0) { zwarn("pcre_exec() error [%d]", r); break; } else if (r>0) { zpcre_get_substrings(lhstr_plain, ov, r, NULL, avar, 0, isset(BASHREMATCH), !isset(BASHREMATCH)); return_value = 1; break; } break; } if (lhstr_plain) free(lhstr_plain); if(rhre_plain) free(rhre_plain); if (pcre_pat) pcre_free(pcre_pat); if (ov) zfree(ov, ovsize*sizeof(int)); return return_value; }
static int bin_pcre_match(char *nam, char **args, Options ops, UNUSED(int func)) { int ret, capcount, *ovec, ovecsize, c; char *matched_portion = NULL; char *plaintext = NULL; char *receptacle = NULL; int return_value = 1; /* The subject length and offset start are both int values in pcre_exec */ int subject_len; int offset_start = 0; int want_offset_pair = 0; if (pcre_pattern == NULL) { zwarnnam(nam, "no pattern has been compiled"); return 1; } if(OPT_HASARG(ops,c='a')) { receptacle = OPT_ARG(ops,c); } if(OPT_HASARG(ops,c='v')) { matched_portion = OPT_ARG(ops,c); } if(OPT_HASARG(ops,c='n')) { /* The offset position to start the search, in bytes. */ offset_start = getposint(OPT_ARG(ops,c), nam); } /* For the entire match, 'Return' the offset byte positions instead of the matched string */ if(OPT_ISSET(ops,'b')) want_offset_pair = 1; if(!*args) { zwarnnam(nam, "not enough arguments"); } if ((ret = pcre_fullinfo(pcre_pattern, pcre_hints, PCRE_INFO_CAPTURECOUNT, &capcount))) { zwarnnam(nam, "error %d in fullinfo", ret); return 1; } ovecsize = (capcount+1)*3; ovec = zalloc(ovecsize*sizeof(int)); plaintext = ztrdup(*args); unmetafy(plaintext, NULL); subject_len = (int)strlen(plaintext); if (offset_start < 0 || offset_start >= subject_len) ret = PCRE_ERROR_NOMATCH; else ret = pcre_exec(pcre_pattern, pcre_hints, plaintext, subject_len, offset_start, 0, ovec, ovecsize); if (ret==0) return_value = 0; else if (ret==PCRE_ERROR_NOMATCH) /* no match */; else if (ret>0) { zpcre_get_substrings(plaintext, ovec, ret, matched_portion, receptacle, want_offset_pair, 0, 0); return_value = 0; } else { zwarnnam(nam, "error in pcre_exec [%d]", ret); } if (ovec) zfree(ovec, ovecsize*sizeof(int)); return return_value; }
static int inputline(void) { char *ingetcline, **ingetcpmptl = NULL, **ingetcpmptr = NULL; int context = ZLCON_LINE_START; /* If reading code interactively, work out the prompts. */ if (interact && isset(SHINSTDIN)) { if (!isfirstln) { ingetcpmptl = &prompt2; if (rprompt2) ingetcpmptr = &rprompt2; context = ZLCON_LINE_CONT; } else { ingetcpmptl = &prompt; if (rprompt) ingetcpmptr = &rprompt; } } if (!(interact && isset(SHINSTDIN) && SHTTY != -1 && isset(USEZLE))) { /* * If not using zle, read the line straight from the input file. * Possibly we don't get the whole line at once: in that case, * we get another chunk with the next call to inputline(). */ if (interact && isset(SHINSTDIN)) { /* * We may still be interactive (e.g. running under emacs), * so output a prompt if necessary. We don't know enough * about the input device to be able to handle an rprompt, * though. */ char *pptbuf; int pptlen; pptbuf = unmetafy(promptexpand(ingetcpmptl ? *ingetcpmptl : NULL, 0, NULL, NULL, NULL), &pptlen); write_loop(2, pptbuf, pptlen); free(pptbuf); } ingetcline = shingetline(); } else { /* * Since we may have to read multiple lines before getting * a complete piece of input, we tell zle not to restore the * original tty settings after reading each chunk. Instead, * this is done when the history mechanism for the current input * terminates, which is not until we have the whole input. * This is supposed to minimise problems on systems that clobber * typeahead when the terminal settings are altered. * pws 1998/03/12 */ int flags = ZLRF_HISTORY|ZLRF_NOSETTY; if (isset(IGNOREEOF)) flags |= ZLRF_IGNOREEOF; ingetcline = zleentry(ZLE_CMD_READ, ingetcpmptl, ingetcpmptr, flags, context); histdone |= HISTFLAG_SETTY; } if (!ingetcline) { return lexstop = 1; } if (errflag) { free(ingetcline); return lexstop = errflag = 1; } if (isset(VERBOSE)) { /* Output the whole line read so far. */ zputs(ingetcline, stderr); fflush(stderr); } if (keyboardhackchar && *ingetcline && ingetcline[strlen(ingetcline) - 1] == '\n' && interact && isset(SHINSTDIN) && SHTTY != -1 && ingetcline[1]) { char *stripptr = ingetcline + strlen(ingetcline) - 2; if (*stripptr == keyboardhackchar) { /* Junk an unwanted character at the end of the line. (key too close to return key) */ int ct = 1; /* force odd */ char *ptr; if (keyboardhackchar == '\'' || keyboardhackchar == '"' || keyboardhackchar == '`') { /* * for the chars above, also require an odd count before * junking */ for (ct = 0, ptr = ingetcline; *ptr; ptr++) if (*ptr == keyboardhackchar) ct++; } if (ct & 1) { stripptr[0] = '\n'; stripptr[1] = '\0'; } } } isfirstch = 1; /* Put this into the input channel. */ inputsetline(ingetcline, INP_FREE); return 0; }
char * zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) { char *s, **bracket; int old_errno = errno; int tmout = getiparam("TMOUT"); #if defined(HAVE_POLL) || defined(HAVE_SELECT) /* may not be set, but that's OK since getiparam() returns 0 == off */ baud = getiparam("BAUD"); costmult = (baud) ? 3840000L / baud : 0; #endif /* ZLE doesn't currently work recursively. This is needed in case a * * select loop is used in a function called from ZLE. vared handles * * this differently itself. */ if(zleactive) { char *pptbuf; int pptlen; pptbuf = unmetafy(promptexpand(lp ? *lp : NULL, 0, NULL, NULL, &pmpt_attr), &pptlen); write_loop(2, pptbuf, pptlen); free(pptbuf); return shingetline(); } /* * The current status is what we need if we are going * to display a prompt. We'll remember it here for * use further in. */ pre_zle_status = lastval; keytimeout = (time_t)getiparam("KEYTIMEOUT"); if (!shout) { if (SHTTY != -1) init_shout(); if (!shout) return NULL; /* We could be smarter and default to a system read. */ /* If we just got a new shout, make sure the terminal is set up. */ if (termflags & TERM_UNKNOWN) init_term(); } fflush(shout); fflush(stderr); intr(); insmode = unset(OVERSTRIKE); eofsent = 0; resetneeded = 0; fetchttyinfo = 0; trashedzle = 0; raw_lp = lp; lpromptbuf = promptexpand(lp ? *lp : NULL, 1, NULL, NULL, &pmpt_attr); raw_rp = rp; rpmpt_attr = pmpt_attr; rpromptbuf = promptexpand(rp ? *rp : NULL, 1, NULL, NULL, &rpmpt_attr); free_prepostdisplay(); zlereadflags = flags; zlecontext = context; histline = curhist; vistartchange = -1; zleline = (ZLE_STRING_T)zalloc(((linesz = 256) + 2) * ZLE_CHAR_SIZE); *zleline = ZWC('\0'); virangeflag = lastcmd = done = zlecs = zlell = mark = 0; vichgflag = 0; viinsbegin = 0; statusline = NULL; selectkeymap("main", 1); initundo(); fixsuffix(); if ((s = getlinknode(bufstack))) { setline(s, ZSL_TOEND); zsfree(s); if (stackcs != -1) { zlecs = stackcs; stackcs = -1; if (zlecs > zlell) zlecs = zlell; CCLEFT(); } if (stackhist != -1) { histline = stackhist; stackhist = -1; } handleundo(); } /* * If main is linked to the viins keymap, we need to register * explicitly that we're now in vi insert mode as there's * no user operation to indicate this. */ if (openkeymap("main") == openkeymap("viins")) viinsert_init(); selectlocalmap(NULL); if (isset(PROMPTCR)) putc('\r', shout); if (tmout) alarm(tmout); /* * On some windowing systems we may enter this function before the * terminal is fully opened and sized, resulting in an infinite * series of SIGWINCH when the handler prints the prompt before we * have done so here. Therefore, hold any such signal until the * first full refresh has completed. The important bit is that the * handler must not see zleactive = 1 until ZLE really is active. * See the end of adjustwinsize() in Src/utils.c */ queue_signals(); zleactive = 1; resetneeded = 1; /* * Start of the main zle read. * Fully reset error conditions, including user interrupt. */ errflag = retflag = 0; lastcol = -1; initmodifier(&zmod); prefixflag = 0; zrefresh(); unqueue_signals(); /* Should now be safe to acknowledge SIGWINCH */ zlecallhook(init, NULL); if ((bracket = getaparam("zle_bracketed_paste")) && arrlen(bracket) == 2) fputs(*bracket, shout); zrefresh(); zlecore(); if (errflag) setsparam((zlecontext == ZLCON_VARED) ? "ZLE_VARED_ABORTED" : "ZLE_LINE_ABORTED", zlegetline(NULL, NULL)); if ((bracket = getaparam("zle_bracketed_paste")) && arrlen(bracket) == 2) fputs(bracket[1], shout); if (done && !exit_pending && !errflag) zlecallhook(finish, NULL); statusline = NULL; invalidatelist(); trashzle(); free(lpromptbuf); free(rpromptbuf); zleactive = zlereadflags = lastlistlen = zlecontext = 0; alarm(0); freeundo(); if (eofsent || errflag || exit_pending) { s = NULL; } else { zleline[zlell++] = ZWC('\n'); s = zlegetline(NULL, NULL); } free(zleline); zleline = NULL; forget_edits(); errno = old_errno; /* highlight no longer valid */ set_region_highlight(NULL, NULL); return s; }
mod_export ZLE_STRING_T stringaszleline(char *instr, int incs, int *outll, int *outsz, int *outcs) { ZLE_STRING_T outstr; int ll, sz, sub; struct region_highlight *rhp; #ifdef MULTIBYTE_SUPPORT mbstate_t mbs; #endif if (outcs) { /* * Take account of Meta characters in the input string * before we unmetafy it. This does not yet take account * of multibyte characters. If there are none, this * is all the processing required to calculate outcs. */ char *inptr = instr, *cspos = instr + incs; if (region_highlights && outcs == &zlecs) { for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; rhp < region_highlights + n_region_highlights; rhp++) { rhp->start = rhp->start_meta; rhp->end = rhp->end_meta; } } while (*inptr) { if (*inptr == Meta) { if (inptr < cspos) { incs--; } if (region_highlights && outcs == &zlecs) { for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; rhp < region_highlights + n_region_highlights; rhp++) { if (rhp->flags & ZRH_PREDISPLAY) sub = predisplaylen; else sub = 0; if (inptr - instr < rhp->start - sub) { rhp->start_meta--; } if (inptr - instr < rhp->end - sub) { rhp->end_meta--; } } } inptr++; } inptr++; } } unmetafy(instr, &ll); /* * ll is the maximum number of characters there can be in * the output string; the closer to ASCII the string, the * better the guess. For the 2 see above. */ sz = (ll + 2) * ZLE_CHAR_SIZE; if (outsz) *outsz = ll; outstr = (ZLE_STRING_T)zalloc(sz); #ifdef MULTIBYTE_SUPPORT if (ll) { char *inptr = instr; wchar_t *outptr = outstr; /* Reset shift state to input complete string */ memset(&mbs, '\0', sizeof mbs); while (ll > 0) { size_t cnt = mbrtowc(outptr, inptr, ll, &mbs); #ifdef __STDC_ISO_10646__ if (cnt == MB_INCOMPLETE || cnt == MB_INVALID) { /* Use private encoding for invalid single byte */ *outptr = ZSH_CHAR_TO_INVALID_WCHAR(*inptr); cnt = 1; } #else /* * At this point we don't handle either incomplete (-2) or * invalid (-1) multibyte sequences. Use the current length * and return. */ if (cnt == MB_INCOMPLETE || cnt == MB_INVALID) break; #endif if (cnt == 0) { /* Converting '\0' returns 0, but a '\0' is a real * character for us, so we should consume 1 byte * (certainly true for Unicode and unlikely to be false * in any non-pathological multibyte representation). */ cnt = 1; } else if (cnt > (size_t)ll) { /* * Some multibyte implementations return the * full length of a previous incomplete character * instead of the remaining length. * This is paranoia: it only applies if we start * midway through a multibyte character, which * presumably can't happen. */ cnt = ll; } if (outcs) { int offs = inptr - instr; if (offs <= incs && incs < offs + (int)cnt) *outcs = outptr - outstr; if (region_highlights && outcs == &zlecs) { for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; rhp < region_highlights + n_region_highlights; rhp++) { if (rhp->flags & ZRH_PREDISPLAY) sub = predisplaylen; else sub = 0; if (offs <= rhp->start_meta - sub && rhp->start_meta - sub < offs + (int)cnt) { rhp->start = outptr - outstr + sub; } if (offs <= rhp->end_meta - sub && rhp->end_meta - sub < offs + (int)cnt) { rhp->end = outptr - outstr + sub; } } } } inptr += cnt; outptr++; ll -= cnt; } if (outcs && inptr <= instr + incs) *outcs = outptr - outstr; *outll = outptr - outstr; } else { *outll = 0; if (outcs) *outcs = 0; } #else memcpy(outstr, instr, ll); *outll = ll; if (outcs) *outcs = incs; if (region_highlights && outcs == &zlecs) { for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; rhp < region_highlights + n_region_highlights; rhp++) { rhp->start = rhp->start_meta; rhp->end = rhp->end_meta; } } #endif return outstr; }
mod_export void showmsg(char const *msg) { char const *p; int up = 0, cc = 0; ZLE_CHAR_T c; #ifdef MULTIBYTE_SUPPORT char *umsg; int ulen, eol = 0; size_t width; mbstate_t mbs; #endif trashzle(); clearflag = isset(USEZLE) && !termflags && isset(ALWAYSLASTPROMPT); #ifdef MULTIBYTE_SUPPORT umsg = ztrdup(msg); p = unmetafy(umsg, &ulen); memset(&mbs, 0, sizeof mbs); mb_metacharinit(); while (ulen > 0) { char const *n; if (*p == '\n') { ulen--; p++; putc('\n', shout); up += 1 + cc / zterm_columns; cc = 0; } else { /* * Extract the next wide character from the multibyte string. */ size_t cnt = eol ? MB_INVALID : mbrtowc(&c, p, ulen, &mbs); switch (cnt) { case MB_INCOMPLETE: eol = 1; /* FALL THROUGH */ case MB_INVALID: /* * This really shouldn't be happening here, but... * Treat it as a single byte character; it may get * prettified. */ memset(&mbs, 0, sizeof mbs); n = nicechar(*p); cnt = 1; width = strlen(n); break; case 0: cnt = 1; /* FALL THROUGH */ default: /* * Paranoia: only needed if we start in the middle * of a multibyte string and only in some implementations. */ if (cnt > (size_t)ulen) cnt = ulen; n = wcs_nicechar(c, &width, NULL); break; } ulen -= cnt; p += cnt; zputs(n, shout); cc += width; } } free(umsg); #else for(p = msg; (c = *p); p++) { if(c == Meta) c = *++p ^ 32; if(c == '\n') { putc('\n', shout); up += 1 + cc / zterm_columns; cc = 0; } else { char const *n = nicechar(c); zputs(n, shout); cc += strlen(n); } } #endif up += cc / zterm_columns; if (clearflag) { putc('\r', shout); tcmultout(TCUP, TCMULTUP, up + nlnct); } else putc('\n', shout); showinglist = 0; }
void hashdir(char **dirp) { Cmdnam cn; DIR *dir; char *fn, *unmetadir, *pathbuf, *pathptr; int dirlen; #if defined(_WIN32) || defined(__CYGWIN__) char *exe; #endif /* _WIN32 || _CYGWIN__ */ if (isrelative(*dirp)) return; unmetadir = unmeta(*dirp); if (!(dir = opendir(unmetadir))) return; dirlen = strlen(unmetadir); pathbuf = (char *)zalloc(dirlen + PATH_MAX + 2); sprintf(pathbuf, "%s/", unmetadir); pathptr = pathbuf + dirlen + 1; while ((fn = zreaddir(dir, 1))) { if (!cmdnamtab->getnode(cmdnamtab, fn)) { char *fname = ztrdup(fn); struct stat statbuf; int add = 0, dummylen; unmetafy(fn, &dummylen); if (strlen(fn) > PATH_MAX) { /* Too heavy to do all the allocation */ add = 1; } else { strcpy(pathptr, fn); /* * This is the same test as for the glob qualifier for * executable plain files. */ if (unset(HASHEXECUTABLESONLY) || (access(pathbuf, X_OK) == 0 && stat(pathbuf, &statbuf) == 0 && S_ISREG(statbuf.st_mode) && (statbuf.st_mode & S_IXUGO))) add = 1; } if (add) { cn = (Cmdnam) zshcalloc(sizeof *cn); cn->node.flags = 0; cn->u.name = dirp; cmdnamtab->addnode(cmdnamtab, fname, cn); } else zsfree(fname); } #if defined(_WIN32) || defined(__CYGWIN__) /* Hash foo.exe as foo, since when no real foo exists, foo.exe will get executed by DOS automatically. This quiets spurious corrections when CORRECT or CORRECT_ALL is set. */ if ((exe = strrchr(fn, '.')) && (exe[1] == 'E' || exe[1] == 'e') && (exe[2] == 'X' || exe[2] == 'x') && (exe[3] == 'E' || exe[3] == 'e') && exe[4] == 0) { *exe = 0; if (!cmdnamtab->getnode(cmdnamtab, fn)) { cn = (Cmdnam) zshcalloc(sizeof *cn); cn->node.flags = 0; cn->u.name = dirp; cmdnamtab->addnode(cmdnamtab, ztrdup(fn), cn); } } #endif /* _WIN32 || __CYGWIN__ */ } closedir(dir); zfree(pathbuf, dirlen + PATH_MAX + 2); }
static int recursivecmd(char *nam, int opt_noerr, int opt_recurse, int opt_safe, char **args, RecurseFunc dirpre_func, RecurseFunc dirpost_func, RecurseFunc leaf_func, void *magic) { int err = 0, len; char *rp, *s; struct dirsav ds; struct recursivecmd reccmd; reccmd.nam = nam; reccmd.opt_noerr = opt_noerr; reccmd.opt_recurse = opt_recurse; reccmd.opt_safe = opt_safe; reccmd.dirpre_func = dirpre_func; reccmd.dirpost_func = dirpost_func; reccmd.leaf_func = leaf_func; reccmd.magic = magic; init_dirsav(&ds); if (opt_recurse || opt_safe) { if ((ds.dirfd = open(".", O_RDONLY|O_NOCTTY)) < 0 && zgetdir(&ds) && *ds.dirname != '/') ds.dirfd = open("..", O_RDONLY|O_NOCTTY); } for(; !errflag && !(err & 2) && *args; args++) { rp = ztrdup(*args); unmetafy(rp, &len); if (opt_safe) { s = strrchr(rp, '/'); if (s && !s[1]) { while (*s == '/' && s > rp) *s-- = '\0'; while (*s != '/' && s > rp) s--; } if (s && s[1]) { int e; *s = '\0'; e = lchdir(s > rp ? rp : "/", &ds, 1); err |= -e; if (!e) { struct dirsav d; d.ino = d.dev = 0; d.dirname = NULL; d.dirfd = d.level = -1; err |= recursivecmd_doone(&reccmd, *args, s + 1, &d, 0); zsfree(d.dirname); if (restoredir(&ds)) err |= 2; } else if(!opt_noerr) zwarnnam(nam, "%s: %e", *args, errno); } else err |= recursivecmd_doone(&reccmd, *args, rp, &ds, 0); } else err |= recursivecmd_doone(&reccmd, *args, rp, &ds, 1); zfree(rp, len + 1); } if ((err & 2) && ds.dirfd >= 0 && restoredir(&ds) && zchdir(pwd)) { zsfree(pwd); pwd = ztrdup("/"); if (chdir(pwd) < 0) zwarn("failed to chdir(%s): %e", pwd, errno); } if (ds.dirfd >= 0) close(ds.dirfd); zsfree(ds.dirname); return !!err; }
static int recursivecmd_dorec(struct recursivecmd const *reccmd, char *arg, char *rp, struct stat const *sp, struct dirsav *ds, int first) { char *fn; DIR *d; int err, err1; struct dirsav dsav; char *files = NULL; int fileslen = 0; err1 = reccmd->dirpre_func(arg, rp, sp, reccmd->magic); if(err1 & 2) return 2; err = -lchdir(rp, ds, !first); if (err) { if(!reccmd->opt_noerr) zwarnnam(reccmd->nam, "%s: %e", arg, errno); return err; } err = err1; init_dirsav(&dsav); d = opendir("."); if(!d) { if(!reccmd->opt_noerr) zwarnnam(reccmd->nam, "%s: %e", arg, errno); err = 1; } else { int arglen = strlen(arg) + 1; while (!errflag && (fn = zreaddir(d, 1))) { int l = strlen(fn) + 1; files = hrealloc(files, fileslen, fileslen + l); strcpy(files + fileslen, fn); fileslen += l; } closedir(d); for (fn = files; !errflag && !(err & 2) && fn < files + fileslen;) { int l = strlen(fn) + 1; VARARR(char, narg, arglen + l); strcpy(narg,arg); narg[arglen-1] = '/'; strcpy(narg + arglen, fn); unmetafy(fn, NULL); err |= recursivecmd_doone(reccmd, narg, fn, &dsav, 0); fn += l; } hrealloc(files, fileslen, 0); } zsfree(dsav.dirname); if (err & 2) return 2; if (restoredir(ds)) { if(!reccmd->opt_noerr) zwarnnam(reccmd->nam, "failed to return to previous directory: %e", errno); return 2; } return err | reccmd->dirpost_func(arg, rp, sp, reccmd->magic); }
static int inputline(void) { char *ingetcline, **ingetcpmptl = NULL, **ingetcpmptr = NULL; int context = ZLCON_LINE_START; /* If reading code interactively, work out the prompts. */ if (interact && isset(SHINSTDIN)) { if (!isfirstln) { ingetcpmptl = &prompt2; if (rprompt2) ingetcpmptr = &rprompt2; context = ZLCON_LINE_CONT; } else { ingetcpmptl = &prompt; if (rprompt) ingetcpmptr = &rprompt; } } if (!(interact && isset(SHINSTDIN) && SHTTY != -1 && isset(USEZLE))) { /* * If not using zle, read the line straight from the input file. * Possibly we don't get the whole line at once: in that case, * we get another chunk with the next call to inputline(). */ if (interact && isset(SHINSTDIN)) { /* * We may still be interactive (e.g. running under emacs), * so output a prompt if necessary. We don't know enough * about the input device to be able to handle an rprompt, * though. */ char *pptbuf; int pptlen; pptbuf = unmetafy(promptexpand(ingetcpmptl ? *ingetcpmptl : NULL, 0, NULL, NULL, NULL), &pptlen); write_loop(2, pptbuf, pptlen); free(pptbuf); } ingetcline = shingetline(); } else { /* * Since we may have to read multiple lines before getting * a complete piece of input, we tell zle not to restore the * original tty settings after reading each chunk. Instead, * this is done when the history mechanism for the current input * terminates, which is not until we have the whole input. * This is supposed to minimise problems on systems that clobber * typeahead when the terminal settings are altered. * pws 1998/03/12 */ int flags = ZLRF_HISTORY|ZLRF_NOSETTY; if (isset(IGNOREEOF)) flags |= ZLRF_IGNOREEOF; ingetcline = zleentry(ZLE_CMD_READ, ingetcpmptl, ingetcpmptr, flags, context); histdone |= HISTFLAG_SETTY; } if (!ingetcline) { return lexstop = 1; } if (errflag) { free(ingetcline); errflag |= ERRFLAG_ERROR; return lexstop = 1; } if (isset(VERBOSE)) { /* Output the whole line read so far. */ zputs(ingetcline, stderr); fflush(stderr); } if (keyboardhackchar && *ingetcline && ingetcline[strlen(ingetcline) - 1] == '\n' && interact && isset(SHINSTDIN) && SHTTY != -1 && ingetcline[1]) { char *stripptr = ingetcline + strlen(ingetcline) - 2; if (*stripptr == keyboardhackchar) { /* Junk an unwanted character at the end of the line. (key too close to return key) */ int ct = 1; /* force odd */ char *ptr; if (keyboardhackchar == '\'' || keyboardhackchar == '"' || keyboardhackchar == '`') { /* * for the chars above, also require an odd count before * junking */ for (ct = 0, ptr = ingetcline; *ptr; ptr++) if (*ptr == keyboardhackchar) ct++; } if (ct & 1) { stripptr[0] = '\n'; stripptr[1] = '\0'; } } } isfirstch = 1; if ((inbufflags & INP_APPEND) && inbuf) { /* * We need new input but need to be able to back up * over the old input, so append this line. * Pushing the line onto the stack doesn't have the right * effect. * * This is quite a simple and inefficient fix, but currently * we only need it when backing up over a multi-line $((... * that turned out to be a command substitution rather than * a math substitution, which is a very special case. * So it's not worth rewriting. */ char *oinbuf = inbuf; int newlen = strlen(ingetcline); int oldlen = (int)(inbufptr - inbuf) + inbufleft; if (inbufflags & INP_FREE) { inbuf = realloc(inbuf, oldlen + newlen + 1); } else { inbuf = zalloc(oldlen + newlen + 1); memcpy(inbuf, oinbuf, oldlen); } inbufptr += inbuf - oinbuf; strcpy(inbuf + oldlen, ingetcline); free(ingetcline); inbufleft += newlen; inbufct += newlen; inbufflags |= INP_FREE; } else { /* Put this into the input channel. */ inputsetline(ingetcline, INP_FREE); } return 0; }
void stradd(char *d) { #ifdef MULTIBYTE_SUPPORT char *ums, *ups; int upslen, eol = 0; mbstate_t mbs; memset(&mbs, 0, sizeof mbs); ums = ztrdup(d); ups = unmetafy(ums, &upslen); /* * We now have a raw string of possibly multibyte characters. * Read each character one by one. */ while (upslen > 0) { wchar_t cc; char *pc; size_t cnt = eol ? MB_INVALID : mbrtowc(&cc, ups, upslen, &mbs); switch (cnt) { case MB_INCOMPLETE: eol = 1; /* FALL THROUGH */ case MB_INVALID: /* Bad character. Take the next byte on its own. */ pc = nicechar(*ups); cnt = 1; memset(&mbs, 0, sizeof mbs); break; case 0: cnt = 1; /* FALL THROUGH */ default: /* Take full wide character in one go */ mb_metacharinit(); pc = wcs_nicechar(cc, NULL, NULL); break; } /* Keep output as metafied string. */ addbufspc(strlen(pc)); upslen -= cnt; ups += cnt; /* Put printed representation into the buffer */ while (*pc) *bv->bp++ = *pc++; } free(ums); #else char *ps, *pc; addbufspc(niceztrlen(d)); /* This loop puts the nice representation of the string into the * prompt buffer. */ for (ps = d; *ps; ps++) { for (pc = nicechar(*ps == Meta ? *++ps^32 : *ps); *pc; pc++) *bv->bp++ = *pc; } #endif }