/* * * zle_misc.c - miscellaneous editor routines * * This file is part of zsh, the Z shell. * * This software is Copyright 1992 by Paul Falstad * * Permission is hereby granted to copy, reproduce, redistribute or otherwise * use this software as long as: there is no monetary profit gained * specifically from the use or reproduction of this software, it is not * sold, rented, traded or otherwise marketed, and this copyright notice is * included prominently in any copy made. * * The author make no claims as to the fitness or correctness of this software * for any use whatsoever, and it is provided as is. Any use of this software * is at the user's own risk. * */ #define ZLE #include "zsh.h" void selfinsert() /**/ { int ncs = cs+mult; if (mult < 0) { mult = -mult; ncs = cs; } if (insmode || ll == cs) spaceinline(mult); else if (mult+cs > ll) spaceinline(ll-(mult+cs)); while (mult--) line[cs++] = c; cs = ncs; } void selfinsertunmeta() /**/ { c &= 0x7f; if (c == '\r') c = '\n'; selfinsert(); } void deletechar() /**/ { if (mult < 0) { mult = -mult; backwarddeletechar(); return; } if (c == 4 && !ll) { eofsent = 1; return; } if (!(cs+mult > ll || line[cs] == '\n')) { cs += mult; backdel(mult); } else feep(); } void backwarddeletechar() /**/ { if (mult < 0) { mult = -mult; deletechar(); return; } if (mult > cs) mult = cs; backdel(mult); } void vibackwarddeletechar() /**/ { if (mult < 0) { mult = -mult; videletechar(); return; } if (mult > cs) mult = cs; if (cs-mult < viinsbegin) { feep(); return; } backkill(mult,1); } void vikillline() /**/ { if (viinsbegin > cs) { feep(); return; } backdel(cs-viinsbegin); } void killwholeline() /**/ { int i,fg; if (mult < 0) return; while (mult--) { if (fg = (cs && cs == ll)) cs--; while (cs && line[cs-1] != '\n') cs--; for (i = cs; i != ll && line[i] != '\n'; i++); forekill(i-cs+(i != ll),fg); } } void killbuffer() /**/ { cs = 0; forekill(ll,0); } void backwardkillline() /**/ { int i = 0; if (mult < 0) { mult = -mult; killline(); return; } while (mult--) { while (cs && line[cs-1] != '\n') cs--,i++; if (mult && cs && line[cs-1] == '\n') cs--,i++; } forekill(i,1); } void gosmacstransposechars() /**/ { int cc; if (cs < 2 || line[cs-1] == '\n' || line[cs-2] == '\n') { if (line[cs] == '\n' || line[cs+1] == '\n') { feep(); return; } cs += (cs == 0 || line[cs-1] == '\n') ? 2 : 1; } cc = line[cs-2]; line[cs-2] = line[cs-1]; line[cs-1] = cc; } void transposechars() /**/ { int cc, ct; int neg = mult < 0; if (neg) mult = -mult; while (mult--) { if (!(ct = cs) || line[cs-1] == '\n') { if (ll == cs || line[cs] == '\n') { feep(); return; } if (!neg) cs++; ct++; } if (neg) { if (cs && line[cs-1] != '\n') { cs--; if (ct > 1 && line[ct-2] != '\n') ct--; } } else { if (cs != ll && line[cs] != '\n') cs++; } if (ct == ll || line[ct] == '\n') ct--; if (ct < 1 || line[ct-1] == '\n') { feep(); return; } cc = line[ct-1]; line[ct-1] = line[ct]; line[ct] = cc; } } void poundinsert() /**/ { if (*line != '#') { cs = 0; spaceinline(1); *line = '#'; } else { cs = 0; foredel(1); } done = 1; } void acceptline() /**/ { done = 1; } void acceptandhold() /**/ { pushnode(bufstack,ztrdup((char *) line)); stackcs = cs; done = 1; } void killline() /**/ { int i = 0; if (mult < 0) { mult = -mult; backwardkillline(); return; } while (mult--) { if (line[cs] == '\n') cs++,i++; while (cs != ll && line[cs] != '\n') cs++,i++; } backkill(i,0); } void killregion() /**/ { if (mark > ll) mark = ll; if (mark > cs) forekill(mark-cs,0); else backkill(cs-mark,1); } void copyregionaskill() /**/ { if (mark > ll) mark = ll; if (mark > cs) cut(cs,mark-cs,0); else cut(mark,cs-mark,1); } static int kct,yankb,yanke; void yank() /**/ { int cc; char *buf = cutbuf; if (!cutbuf) { feep(); return; } if (mult < 0) return; if (vibufspec) { vibufspec = tolower(vibufspec); vibufspec += (idigit(vibufspec)) ? -'1'+26 : -'a'; if (!(buf = vibuf[vibufspec])) { feep(); vibufspec = 0; return; } vibufspec = 0; } yankb = cs; while (mult--) { kct = kringnum; cc = strlen(buf); spaceinline(cc); strncpy((char *) line+cs,buf,cc); cs += cc; yanke = cs; } } void viputafter() /**/ { int cc; char *buf = cutbuf; if (!cutbuf) { feep(); return; } if (mult < 0) return; if (vibufspec) { vibufspec = tolower(vibufspec); vibufspec += (idigit(vibufspec)) ? -'1'+26 : -'a'; if (!(buf = vibuf[vibufspec])) { feep(); vibufspec = 0; return; } vibufspec = 0; } if (strchr(buf,'\n')) { cs = findeol(); if (cs == ll) { spaceinline(1); line[cs] = '\n'; } } if (cs != ll) cs++; yankb = cs; while (mult--) { kct = kringnum; cc = strlen(buf); spaceinline(cc); strncpy((char *) line+cs,buf,cc); cs += cc; yanke = cs; } cs = yankb; } void yankpop() /**/ { int cc; if (!(lastcmd & ZLE_YANK) || !kring[kct]) { feep(); return; } cs = yankb; foredel(yanke-yankb); cc = strlen(kring[kct]); spaceinline(cc); strncpy((char *) line+cs,kring[kct],cc); cs += cc; yanke = cs; kct = (kct-1) & (KRINGCT-1); } void overwritemode() /**/ { insmode ^= 1; } void undefinedkey() /**/ { feep(); } void quotedinsert() /**/ { #ifndef TIO struct sgttyb sob; sob = shttyinfo.sgttyb; sob.sg_flags = (sob.sg_flags|RAW) & ~ECHO; ioctl(SHTTY,TIOCSETN,&sob); #endif c = getkey(0); #ifndef TIO setterm(); #endif if (c) selfinsert(); else feep(); } void digitargument() /**/ { int sign = (mult < 0 || (lastcmd & ZLE_NEGARG)) ? -1 : 1; if ((lastcmd & (ZLE_ARG|ZLE_NEGARG)) != ZLE_ARG) mult = 0; mult = mult*10 + sign*(c&0xf); } void negargument() /**/ { if (lastcmd & ZLE_ARG) feep(); mult = -1; } void universalargument() /**/ { if (!(lastcmd & ZLE_ARG)) mult = 4; else mult *= 4; } void copyprevword() /**/ { int len,t0; for (t0 = cs-1; t0 >= 0; t0--) if (iword(line[t0])) break; for (; t0 >= 0; t0--) if (!iword(line[t0])) break; if (t0) t0++; len = cs-t0; spaceinline(len); strncpy((char *) line+cs,(char *) line+t0,len); cs += len; } void sendbreak() /**/ { errflag = done = 1; } void undo() /**/ { char *s; struct undoent *ue; ue = undos+undoct; if (!ue->change) { feep(); return; } line[ll] = '\0'; s = ztrdup((char *) line+ll-ue->suff); sizeline((ll = ue->pref+ue->suff+ue->len)+1); strncpy((char *) line+ue->pref,ue->change,ue->len); strcpy((char *) line+ue->pref+ue->len,s); free(s); ue->change = NULL; undoct = (undoct-1) & (UNDOCT-1); cs = ue->cs; } void quoteregion() /**/ { char *s,*t; int x,y; if (mark > ll) mark = ll; if (mark < cs) { x = mark; mark = cs; cs = x; } s = hcalloc((y = mark-cs)+1); strncpy(s,(char *) line+cs,y); s[y] = '\0'; foredel(mark-cs); t = makequote(s); spaceinline(x = strlen(t)); strncpy((char *) line+cs,t,x); mark = cs; cs += x; } void quoteline() /**/ { char *s; line[ll] = '\0'; s = makequote((char *) line); setline(s); } char *makequote(s) /**/ char *s; { int qtct = 0; char *l,*ol; for (l = s; *l; l++) if (*l == '\'') qtct++; l = ol = halloc((qtct*3)+3+strlen(s)); *l++ = '\''; for (; *s; s++) if (*s == '\'') { *l++ = '\''; *l++ = '\\'; *l++ = '\''; *l++ = '\''; } else *l++ = *s; *l++ = '\''; *l = '\0'; return ol; } #define NAMLEN 70 int executenamedcommand() /**/ { char buf[NAMLEN],*ptr; int len,ch,t0; strcpy(buf,"execute: "); ptr = buf+9; len = 0; statusline = buf; refresh(); for (;ch = getkey(1);refresh()) { switch (ch) { case 8: case 127: if (len) { len--; *--ptr = '\0'; } break; case 23: while (len && (len--, *--ptr != '-')) *ptr = '\0'; break; case 21: len = 0; ptr = buf+9; *ptr = '\0'; break; case 10: case 13: goto brk; case 7: case -1: statusline = NULL; return z_undefinedkey; case 9: case 32: { Lklist ll; int ambig = 100; heapalloc(); ll = newlist(); for (t0 = 0; t0 != ZLECMDCOUNT; t0++) if (strpfx(buf+9,zlecmds[t0].name)) { int xx; addnode(ll,zlecmds[t0].name); xx = pfxlen(peekfirst(ll),zlecmds[t0].name); if (xx < ambig) ambig = xx; } permalloc(); if (empty(ll)) feep(); else if (!nextnode(firstnode(ll))) { strcpy(buf+9,peekfirst(ll)); ptr = buf+(len = strlen(buf)); } else { strcpy(buf+9,peekfirst(ll)); len = ambig; ptr = buf+9+len; *ptr = '\0'; feep(); listmatches(ll,NULL); } break; } default: if (len == NAMLEN-10 || icntrl(ch)) feep(); else *ptr++ = ch, *ptr = '\0', len++; break; } } brk: statusline = NULL; ptr = buf+9; for (t0 = 0; t0 != ZLECMDCOUNT; t0++) if (!strcmp(ptr,zlecmds[t0].name)) break; if (t0 != ZLECMDCOUNT) return lastnamed = t0; else return z_undefinedkey; } void vijoin() /**/ { int x; if ((x = findeol()) == ll) { feep(); return; } cs = x+1; for (x = 1; cs != ll && iblank(line[cs]); cs++,x++); backdel(x); spaceinline(1); line[cs] = ' '; } void viswapcase() /**/ { if (cs < ll) { int ch = line[cs]; if (islower(ch)) ch = tuupper(ch); else if (isupper(ch)) ch = tulower(ch); line[cs++] = ch; } } void vicapslockpanic() /**/ { char ch; statusline = "press a lowercase key to continue"; refresh(); do ch = getkey(0); while (!islower(ch)); } void visetbuffer() /**/ { int ch; ch = getkey(1); if (!ialnum(ch)) { feep(); return; } vibufspec = ch; } static char *bp; static int lensb,countp; void stradd(d) /**/ char *d; { while (*bp++ = *d++); bp--; } int putstr(d) /**/ int d; { *bp++ = d; if (countp) lensb++; return 0; } #define tstradd(X) \ if (termok && unset(SINGLELINEZLE)) { \ char tbuf[2048],*tptr = tbuf; \ if (tgetstr(X,&tptr)) \ tputs(tbuf,1,putstr); \ } \ break /* get a prompt string */ char *putprompt(fm,lenp,isspell) /**/ char *fm;int *lenp;int isspell; { char *ss,*bl0; static char buf0[256],buf1[256],buf2[256],*buf; char buf3[MAXPATHLEN]; int t0,bracepos = 0,arg; struct tm *tm; time_t timet; lensb = 0; countp = 1; if (!fm) { *lenp = 0; return ""; } /* KLUDGE ALERT! What we have here are three buffers: * buf1 and buf2 alternate between PS1 and PS2, though which is * which is indeterminate depending on spellchecking, "select", * etc. -- those operations also share these two buffers. * buf0 is used for any prompting that manages to happen while * zleread() is in progress (signal traps, etc.), because * zleread() re-uses the pointers returned to buf1 and buf2 * and will be confused if either of those is overwritten. */ buf = zleactive ? buf0 : ((buf == buf1) ? buf2 : buf1); bp = bl0 = buf; if (!columns) columns = 80; clearerr(stdin); for(;*fm;fm++) { if (bp-buf >= 220) break; arg = 0; if (*fm == '%') { if (idigit(*++fm)) { arg = zstrtol(fm, &fm, 10); } switch (*fm) { case '~': t0 = finddir(pwd); if (t0 != -1) { *bp++ = '~'; stradd(usernames[t0]); stradd(pwd+strlen(userdirs[t0])); break; } case 'd': case '/': stradd(pwd); break; case 'c': case '.': t0 = finddir(pwd); if (t0 != -1) { sprintf(buf3,"~%s%s",usernames[t0], pwd+strlen(userdirs[t0])); } else { strcpy(buf3,pwd); } if (!arg) arg++; for (ss = buf3+strlen(buf3); ss > buf3; ss--) if (*ss == '/' && !--arg) { ss++; break; } if (*ss == '/' && ss[1] && (ss != buf3)) ss++; stradd(ss); break; case 'C': strcpy(buf3,pwd); if (!arg) arg++; for (ss = buf3+strlen(buf3); ss > buf3; ss--) if (*ss == '/' && !--arg) { ss++; break; } if (*ss == '/' && ss[1] && (ss != buf3)) ss++; stradd(ss); break; case 'h': case '!': sprintf(bp,"%d",curhist); bp += strlen(bp); break; case 'M': stradd(hostnam); break; case 'm': if (!arg) arg++; for (ss = hostnam; *ss; ss++) if (*ss == '.' && !--arg) break; t0 = *ss; *ss = '\0'; stradd(hostnam); *ss = t0; break; case 'S': tstradd("so"); /* <- this is a macro */ case 's': tstradd("se"); case 'B': tstradd("md"); case 'b': tstradd("me"); case 'U': tstradd("us"); case 'u': tstradd("ue"); case '{': bracepos = bp-buf; countp = 0; break; case '}': lensb += (bp-buf)-bracepos; countp = 1; break; case 't': case '@': timet = time(NULL); tm = localtime(&timet); ztrftime(bp,16,"%l:%M%p",tm); if (*bp == ' ') chuck(bp); bp += strlen(bp); break; case 'T': timet = time(NULL); tm = localtime(&timet); ztrftime(bp,16,"%k:%M",tm); bp += strlen(bp); break; case '*': timet = time(NULL); tm = localtime(&timet); ztrftime(bp,16,"%k:%M:%S",tm); bp += strlen(bp); break; case 'n': stradd(username); break; case 'w': timet = time(NULL); tm = localtime(&timet); ztrftime(bp,16,"%a %e",tm); bp += strlen(bp); break; case 'W': timet = time(NULL); tm = localtime(&timet); ztrftime(bp,16,"%m/%d/%y",tm); bp += strlen(bp); break; case 'D': strcpy(buf3, "%y-%m-%d"); if (fm[1] == '{') { for (ss = fm + 1, t0 = 0; *ss; ++ss) if (*ss == '{') ++t0; else if (*ss == '}') if (--t0 == 0) break; if (*ss == '}' && t0 == 0) { t0 = (ss - 1) - (fm + 1); strncpy(buf3, fm + 2, t0); buf3[t0] = 0; fm = ss; } } timet = time(NULL); tm = localtime(&timet); ztrftime(bp,16,buf3,tm); bp += strlen(bp); break; case 'l': if (*ttystrname) stradd((strncmp(ttystrname,"/dev/tty",8) ? ttystrname+5 : ttystrname+8)); else stradd("()"); break; case '?': sprintf(bp,"%d",lastval); bp += strlen(bp); break; case '%': *bp++ = '%'; break; case '#': *bp++ = (geteuid()) ? '%' : '#'; break; case 'v': if (!arg) arg++; /* The number 35 here comes from 256-220-1, where 256 is * sizeof(buf), 220 is from the overflow test made at the * top of the loop, and 1 is for the \0 byte at the end. */ if (arrlen(psvar) >= arg && strlen(psvar[arg-1]) < 35) stradd(psvar[arg-1]); else stradd(""); break; case 'r': if (isspell) { stradd(rstring); break; } case 'R': if (isspell) { stradd(Rstring); break; } default: *bp++ = '%'; *bp++ = *fm; break; } } else if (*fm == '!') { sprintf(bp,"%d",curhist); bp += strlen(bp); } else { if (fm[0] == '\\' && fm[1]) fm++; if ((*bp++ = *fm) == '\n') bl0 = bp, lensb = 0; } } *lenp = (bp-bl0)-lensb; *lenp %= columns; if (*lenp == columns-1) { *lenp = 0; *bp++ = ' '; } *bp = '\0'; return buf; }