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