|
|
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: char *shellname; ! 151: main(argc, argv) ! 152: char *argv[]; ! 153: { ! 154: register FILE *f; FILE *getline(); ! 155: register nsubst, i; ! 156: char *strchr(); ! 157: int edit=0; ! 158: int print=0; ! 159: cmd=argv[0]; ! 160: if(cmd[0]!='\0'){ ! 161: if(cmd[1]==cmd[0]) ! 162: edit++; ! 163: if(cmd[1]=='p' || cmd[1]!='\0' && cmd[2]=='p') ! 164: print++; ! 165: } ! 166: for(nsubst=0;argc>1 && strchr(argv[argc-1], cmd[0])!=NULL;nsubst++) ! 167: --argc; ! 168: histname=getenv("HISTORY"); ! 169: shellname=getenv("SHELL"); ! 170: if (shellname == 0 || *shellname == 0) ! 171: shellname = "/bin/sh"; ! 172: f = getline(argc, argv); ! 173: for(i=0;i!=nsubst;i++) ! 174: alter(argv[argc+i]); ! 175: if(edit){ ! 176: if((tty=fopen("/dev/tty", "r"))==0) ! 177: tty=stdin; ! 178: xform(f); ! 179: } ! 180: fclose(f); ! 181: if((f=fopen(histname, "a"))!=NULL){ ! 182: fprintf(f, "%s\n", linebuf); ! 183: fclose(f); ! 184: } ! 185: if(print) ! 186: dumpline(1); ! 187: else{ ! 188: if(!edit) ! 189: dumpline(2); ! 190: execl(shellname, "sh", "-c", linebuf, (char *)0); ! 191: error("No shell!\n"); ! 192: } ! 193: } ! 194: dumpline(fd){ ! 195: /* write on fd directly for speed */ ! 196: write(fd, linebuf, strlen(linebuf)); ! 197: write(2, "\n", 1); ! 198: } ! 199: /* ! 200: * Look at $HISTORY. If argc==1 get the last non-blank line in the file. ! 201: * Otherwise, argv[1] is a pattern to match against the lines of the history ! 202: * file. The last matching line wins. ! 203: */ ! 204: FILE * ! 205: getline(argc, argv) ! 206: char *argv[]; ! 207: { ! 208: char history[LBSIZE]; ! 209: char pat[LBSIZE]; ! 210: register char *hp; ! 211: register FILE *f; ! 212: register i; ! 213: int nmatch=0, ntell; ! 214: if(histname==NULL) ! 215: error("Environment lacks HISTORY\n"); ! 216: if((f=fopen(histname, "r"))==NULL){ ! 217: perror(histname); ! 218: exit(1); ! 219: } ! 220: pat[0]='\0'; ! 221: for(i=1;i!=argc && argv[i][0]!=cmd[0];i++){ ! 222: strcat(pat, argv[i]); ! 223: strcat(pat, " "); ! 224: } ! 225: pat[strlen(pat)-1]='\0'; /* annul the extra space */ ! 226: while(ntell=ftell(f), fgets(history, LBSIZE, f)){ ! 227: /* ! 228: * Skip leading blanks or tabs ! 229: */ ! 230: for(hp=history;*hp==' '||*hp=='\t';hp++) ! 231: ; ! 232: if(anyequals(hp)) ! 233: continue; ! 234: /* ! 235: * Welcome to the land of snakey logic ! 236: */ ! 237: if(pat[0]=='\0'?!empty(hp):match(hp, pat)){ ! 238: linesave(ntell, nmatch++); ! 239: strncpy(linebuf, hp, LBSIZE); ! 240: } ! 241: } ! 242: if(nmatch==0) ! 243: error("Can't find a line to redo"); ! 244: linebuf[strlen(linebuf)-1]='\0'; /* delete a newline */ ! 245: return f; ! 246: } ! 247: ! 248: #define VECSIZE 512 ! 249: int *matchvec, *matchend, *lastmatch, *lastuniq, vecsize; ! 250: ! 251: linesave(adr, i) ! 252: { ! 253: if (matchvec == 0) ! 254: matchend = matchvec = Malloc(int, vecsize = VECSIZE); ! 255: if (i >= vecsize) ! 256: matchvec = Realloc(int, matchvec, vecsize += VECSIZE); ! 257: if (matchvec == 0) ! 258: return; ! 259: *matchend++ = adr; ! 260: } ! 261: ! 262: prevline(f) ! 263: FILE *f; ! 264: { ! 265: char history[LBSIZE]; char *strchr(), *savestr(); ! 266: register char *hp; register int *ip; ! 267: if (matchvec == 0) ! 268: return; ! 269: if (lastmatch == 0) ! 270: lastuniq = matchend, lastmatch = --matchend; ! 271: *--lastuniq = (int)savestr(linebuf); ! 272: do { ! 273: if (--lastmatch < matchvec) { ! 274: matchvec = 0; ! 275: return; ! 276: } ! 277: fseek(f, *lastmatch, 0); ! 278: fgets(history, LBSIZE, f); ! 279: for(hp=history;*hp==' '||*hp=='\t';hp++) ! 280: ; ! 281: *strchr(hp,'\n') = '\0'; ! 282: for (ip=lastuniq; ip <= matchend; ip++) ! 283: if (strcmp((char *)(*ip), hp) == 0) break; ! 284: } while (ip <= matchend); ! 285: strncpy(linebuf, hp, LBSIZE); ! 286: } ! 287: ! 288: char * ! 289: savestr(str) /* Place string into permanent storage. */ ! 290: register char *str; ! 291: { ! 292: static int nchleft; static char *strpt; ! 293: register int len; char *strcpy(); ! 294: ! 295: if ((len = strlen(str)+1) > nchleft) { ! 296: strpt = malloc(nchleft = 2*LBSIZE); ! 297: } ! 298: if (strpt == 0) ! 299: return 0; ! 300: str = strcpy(strpt, str); ! 301: strpt += len; nchleft -= len; ! 302: return str; ! 303: } ! 304: ! 305: /* ! 306: * Throw away any command with an = or == word ! 307: */ ! 308: anyequals(line) ! 309: register char *line; ! 310: { ! 311: register char *p, *q; ! 312: for(p=line; *p; p++) ! 313: if(*p=='=' && (p==line || p[-1]==' ' || p[-1]=='\t')){ ! 314: if(p[1]=='=') ! 315: p++; ! 316: if(p[1]=='\n' || p[1]==' ' || p[1]=='\t') ! 317: return 1; ! 318: } ! 319: return 0; ! 320: } ! 321: match(s, p) ! 322: register char *s, *p; ! 323: { ! 324: register char *h; ! 325: for(h=s;*s!='\n' && *s!=' ' && *s!='\t' && *s!='\0';s++) ! 326: if(*s=='/') ! 327: h=s+1; ! 328: return(startis(h, p)); ! 329: } ! 330: startis(s, p) ! 331: register char *s, *p; ! 332: { ! 333: while(*p!='\0') ! 334: if(*p==' '){ ! 335: if(*s!=' ' && *s!='\t') ! 336: return(0); ! 337: while(*s==' ' || *s=='\t') ! 338: s++; ! 339: p++; ! 340: } ! 341: else if(*s++ != *p++) ! 342: return(0); ! 343: return(1); ! 344: } ! 345: empty(s) ! 346: register char *s; ! 347: { ! 348: if(*s==cmd[0]) ! 349: return(1); ! 350: while(*s!='\0'){ ! 351: if(*s!=' ' && *s!='\t' && *s!='\n') ! 352: return(0); ! 353: s++; ! 354: } ! 355: return(1); ! 356: } ! 357: alter(pat) ! 358: register char *pat; ! 359: { ! 360: register char *sub, *s=linebuf, *t=genbuf; ! 361: int patlen, sublen, matched=0; ! 362: for(sub=pat;*sub!=cmd[0] && *sub!='\0';sub++); ! 363: if(*sub!=cmd[0]) ! 364: error("Bad Substitution"); ! 365: patlen=sub-pat; ! 366: if(*sub==cmd[0]) ! 367: *sub++='\0'; ! 368: sublen=strlen(sub); ! 369: while(*s) ! 370: if(!matched && startis(s, pat)){ ! 371: matched++; ! 372: s+=patlen; ! 373: strcpy(t, sub); ! 374: t+=sublen; ! 375: } ! 376: else ! 377: *t++ = *s++; ! 378: if(!matched) ! 379: error("No pattern match"); ! 380: *t='\0'; ! 381: strcpy(linebuf, genbuf); ! 382: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.