|
|
1.1 ! root 1: /*% cc -O % ! 2: * =, == -- redo commands from history ! 3: */ ! 4: #include <stdio.h> ! 5: #define TRUE 1 ! 6: #define FALSE 0 ! 7: #define LBSIZE 512 ! 8: ! 9: char *malloc(), *realloc(); ! 10: ! 11: #define Malloc(type,size) ((type *)malloc((size)*sizeof(type))) ! 12: #define Realloc(type,ptr,size) ((type *)realloc(ptr,(size)*sizeof(type))) ! 13: ! 14: char linebuf[LBSIZE]; ! 15: char *linebp; ! 16: char *getenv(); ! 17: char *cmd; ! 18: char genbuf[LBSIZE]; ! 19: #define RHSIZE 512 ! 20: char rhsbuf[RHSIZE]; ! 21: FILE *tty; ! 22: int nextcol(col,cp,input) ! 23: register col; ! 24: register char *cp; ! 25: int input; ! 26: { ! 27: register char c; ! 28: c = *cp; ! 29: if (c=='\t') ! 30: col |= 07; ! 31: else if (c<' ' || c=='\177') ! 32: error("Invalid character in command"); ! 33: return (++col); ! 34: } ! 35: xform(hfile) ! 36: FILE *hfile; ! 37: { ! 38: register char *i, *m, *o; ! 39: int *line, insert, ic, mc, c; ! 40: char *tf, *tl; ! 41: for(;;){ ! 42: dumpline(2); ! 43: m=rhsbuf; ! 44: while ((c = getc(tty))!='\n') { ! 45: if (c == EOF) ! 46: exit(0); ! 47: *m++ = c; ! 48: if (m==rhsbuf+RHSIZE-1) ! 49: error("Out of space"); ! 50: } ! 51: *m='\0'; ! 52: if (m==rhsbuf) ! 53: break; ! 54: if (rhsbuf[0] == '=' && rhsbuf[1] == 0) { ! 55: prevline(hfile); ! 56: continue; ! 57: } ! 58: i=linebuf; ! 59: o=genbuf; ! 60: do ; while (*o++ = *i++); ! 61: if (i+(m-rhsbuf) > linebuf+LBSIZE) ! 62: error("Out of space"); ! 63: i=genbuf; ! 64: o=linebuf; ! 65: m=rhsbuf; ! 66: insert=FALSE; ! 67: ic=0; ! 68: mc=0; ! 69: while (*i && *m && !insert) { ! 70: if(*i=='\t' && *m!='#' && *m!='^' && *m!='$') { ! 71: ic=nextcol(ic,i,FALSE); ! 72: tf=m; ! 73: tl=m; ! 74: do { ! 75: if (*m!=' ' && *m!='\t') { ! 76: if(*m=='%') ! 77: *m=' '; ! 78: tl=m+1; ! 79: } ! 80: mc=nextcol(mc,m++,TRUE); ! 81: } while (ic>mc && *m && *m!='#' && ! 82: *m!='^' && *m!='$'); ! 83: if (ic>mc) { ! 84: ic=mc; ! 85: if (*m) ! 86: tl=m; ! 87: } else { ! 88: if (tl==m) ! 89: i++; ! 90: else ! 91: ic--; ! 92: } ! 93: while (tf!=tl) ! 94: *o++ = *tf++; ! 95: } else { ! 96: mc=nextcol(mc,m,TRUE); ! 97: *o = *m; ! 98: switch (*m++) { ! 99: case ' ': ! 100: case '\t': ! 101: break; ! 102: case '^': ! 103: mc=ic; ! 104: insert++; ! 105: break; ! 106: case '$': ! 107: i=""; ! 108: break; ! 109: case '#': ! 110: ic=nextcol(ic,i++,FALSE); ! 111: while(*m=='#' && ic>mc) ! 112: mc=nextcol(mc,m++,TRUE); ! 113: if (ic!=mc) ! 114: error("Partly deleted tab"); ! 115: break; ! 116: case '%': ! 117: *o = ' '; ! 118: /* fall through */ ! 119: default: ! 120: o++; ! 121: ic=nextcol(ic,i++,FALSE); ! 122: } ! 123: } ! 124: for (;;) { ! 125: if (ic>mc && *m) { ! 126: if (*m!=' ' && *m!='\t') ! 127: error("Skipped non-blank"); ! 128: mc=nextcol(mc,m++,TRUE); ! 129: } else if (mc>ic && *i) { ! 130: ic=nextcol(ic,i,FALSE); ! 131: *o++ = *i++; ! 132: } else ! 133: break; ! 134: } ! 135: } ! 136: if (mc>ic && m[-1]=='\t') ! 137: *o++ = '\t'; ! 138: while (*m) ! 139: *o++ = *m++; ! 140: do ; while (*o++ = *i++); ! 141: } ! 142: } ! 143: error(s) ! 144: char *s; ! 145: { ! 146: fprintf(stderr, "%s: %s\n", cmd, s); ! 147: exit(1); ! 148: } ! 149: char *histname; ! 150: main(argc, argv) ! 151: char *argv[]; ! 152: { ! 153: register FILE *f; FILE *getline(); ! 154: register nsubst, i; ! 155: char *strchr(); ! 156: int edit=0; ! 157: int print=0; ! 158: cmd=argv[0]; ! 159: if(cmd[0]!='\0'){ ! 160: if(cmd[1]==cmd[0]) ! 161: edit++; ! 162: if(cmd[1]=='p' || cmd[1]!='\0' && cmd[2]=='p') ! 163: print++; ! 164: } ! 165: for(nsubst=0;argc>1 && strchr(argv[argc-1], cmd[0])!=NULL;nsubst++){ ! 166: --argc; ! 167: edit=0; ! 168: } ! 169: histname=getenv("HISTORY"); ! 170: f = getline(argc, argv); ! 171: for(i=0;i!=nsubst;i++) ! 172: alter(argv[argc+i]); ! 173: if(edit){ ! 174: if((tty=fopen("/dev/tty", "r"))==0) ! 175: tty=stdin; ! 176: xform(f); ! 177: } ! 178: fclose(f); ! 179: if((f=fopen(histname, "a"))!=NULL){ ! 180: fprintf(f, "%s\n", linebuf); ! 181: fclose(f); ! 182: } ! 183: if(print) ! 184: dumpline(1); ! 185: else{ ! 186: if(!edit) ! 187: dumpline(2); ! 188: execl("/bin/sh", "sh", "-c", linebuf, (char *)0); ! 189: error("No shell!\n"); ! 190: } ! 191: } ! 192: dumpline(fd){ ! 193: /* write on fd directly for speed */ ! 194: write(fd, linebuf, strlen(linebuf)); ! 195: write(2, "\n", 1); ! 196: } ! 197: /* ! 198: * Look at $HISTORY. If argc==1 get the last non-blank line in the file. ! 199: * Otherwise, argv[1] is a pattern to match against the lines of the history ! 200: * file. The last matching line wins. ! 201: */ ! 202: FILE * ! 203: getline(argc, argv) ! 204: char *argv[]; ! 205: { ! 206: char history[LBSIZE]; ! 207: char pat[LBSIZE]; ! 208: register char *hp; ! 209: register FILE *f; ! 210: register i; ! 211: int nmatch=0, ntell; ! 212: if(histname==NULL) ! 213: error("Environment lacks HISTORY\n"); ! 214: if((f=fopen(histname, "r"))==NULL){ ! 215: perror(histname); ! 216: exit(1); ! 217: } ! 218: pat[0]='\0'; ! 219: for(i=1;i!=argc && argv[i][0]!=cmd[0];i++){ ! 220: strcat(pat, argv[i]); ! 221: strcat(pat, " "); ! 222: } ! 223: pat[strlen(pat)-1]='\0'; /* annul the extra space */ ! 224: while(ntell=ftell(f), fgets(history, LBSIZE, f)){ ! 225: /* ! 226: * Skip leading blanks or tabs ! 227: */ ! 228: for(hp=history;*hp==' '||*hp=='\t';hp++) ! 229: ; ! 230: if(anyequals(hp)) ! 231: continue; ! 232: /* ! 233: * Welcome to the land of snakey logic ! 234: */ ! 235: if(pat[0]=='\0'?!empty(hp):match(hp, pat)){ ! 236: linesave(ntell, nmatch++); ! 237: strncpy(linebuf, hp, LBSIZE); ! 238: } ! 239: } ! 240: if(nmatch==0) ! 241: error("Can't find a line to redo"); ! 242: linebuf[strlen(linebuf)-1]='\0'; /* delete a newline */ ! 243: return f; ! 244: } ! 245: ! 246: #define VECSIZE 512 ! 247: int *matchvec, *matchend, *lastmatch, *lastuniq, vecsize; ! 248: ! 249: linesave(adr, i) ! 250: { ! 251: if (matchvec == 0) ! 252: matchend = matchvec = Malloc(int, vecsize = VECSIZE); ! 253: if (i >= vecsize) ! 254: matchvec = Realloc(int, matchvec, vecsize += VECSIZE); ! 255: if (matchvec == 0) ! 256: return; ! 257: *matchend++ = adr; ! 258: } ! 259: ! 260: prevline(f) ! 261: FILE *f; ! 262: { ! 263: char history[LBSIZE]; char *strchr(), *savestr(); ! 264: register char *hp; register int *ip; ! 265: if (matchvec == 0) ! 266: return; ! 267: if (lastmatch == 0) ! 268: lastuniq = matchend, lastmatch = --matchend; ! 269: *--lastuniq = (int)savestr(linebuf); ! 270: do { ! 271: if (--lastmatch < matchvec) { ! 272: matchvec = 0; ! 273: return; ! 274: } ! 275: fseek(f, *lastmatch, 0); ! 276: fgets(history, LBSIZE, f); ! 277: for(hp=history;*hp==' '||*hp=='\t';hp++) ! 278: ; ! 279: *strchr(hp,'\n') = '\0'; ! 280: for (ip=lastuniq; ip <= matchend; ip++) ! 281: if (strcmp((char *)(*ip), hp) == 0) break; ! 282: } while (ip <= matchend); ! 283: strncpy(linebuf, hp, LBSIZE); ! 284: } ! 285: ! 286: char * ! 287: savestr(str) /* Place string into permanent storage. */ ! 288: register char *str; ! 289: { ! 290: static int nchleft; static char *strpt; ! 291: register int len; char *strcpy(); ! 292: ! 293: if ((len = strlen(str)+1) > nchleft) { ! 294: strpt = malloc(nchleft = 2*LBSIZE); ! 295: } ! 296: if (strpt == 0) ! 297: return 0; ! 298: str = strcpy(strpt, str); ! 299: strpt += len; nchleft -= len; ! 300: return str; ! 301: } ! 302: ! 303: /* ! 304: * Throw away any command with an = or == word ! 305: */ ! 306: anyequals(line) ! 307: register char *line; ! 308: { ! 309: register char *p, *q; ! 310: for(p=line; *p; p++) ! 311: if(*p=='=' && (p==line || p[-1]==' ' || p[-1]=='\t')){ ! 312: if(p[1]=='=') ! 313: p++; ! 314: if(p[1]=='\n' || p[1]==' ' || p[1]=='\t') ! 315: return 1; ! 316: } ! 317: return 0; ! 318: } ! 319: match(s, p) ! 320: register char *s, *p; ! 321: { ! 322: register char *h; ! 323: for(h=s;*s!='\n' && *s!=' ' && *s!='\t' && *s!='\0';s++) ! 324: if(*s=='/') ! 325: h=s+1; ! 326: return(startis(h, p)); ! 327: } ! 328: startis(s, p) ! 329: register char *s, *p; ! 330: { ! 331: while(*p!='\0') ! 332: if(*p==' '){ ! 333: if(*s!=' ' && *s!='\t') ! 334: return(0); ! 335: while(*s==' ' || *s=='\t') ! 336: s++; ! 337: p++; ! 338: } ! 339: else if(*s++ != *p++) ! 340: return(0); ! 341: return(1); ! 342: } ! 343: empty(s) ! 344: register char *s; ! 345: { ! 346: if(*s==cmd[0]) ! 347: return(1); ! 348: while(*s!='\0'){ ! 349: if(*s!=' ' && *s!='\t' && *s!='\n') ! 350: return(0); ! 351: s++; ! 352: } ! 353: return(1); ! 354: } ! 355: alter(pat) ! 356: register char *pat; ! 357: { ! 358: register char *sub, *s=linebuf, *t=genbuf; ! 359: int patlen, sublen, matched=0; ! 360: for(sub=pat;*sub!=cmd[0] && *sub!='\0';sub++); ! 361: if(*sub!=cmd[0]) ! 362: error("Bad Substitution"); ! 363: patlen=sub-pat; ! 364: if(*sub==cmd[0]) ! 365: *sub++='\0'; ! 366: sublen=strlen(sub); ! 367: while(*s) ! 368: if(!matched && startis(s, pat)){ ! 369: matched++; ! 370: s+=patlen; ! 371: strcpy(t, sub); ! 372: t+=sublen; ! 373: } ! 374: else ! 375: *t++ = *s++; ! 376: if(!matched) ! 377: error("No pattern match"); ! 378: *t='\0'; ! 379: strcpy(linebuf, genbuf); ! 380: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.