/* * Csh - shell by PJAC * hist.c - history handling routines */ #include "csh.h" extern char hist_expand; /* * called from readin - do history expansion */ get_hist(mmask) { int c; int i; char *p, *q; int sstart; int scar; char tbuf[128]; switch( c = in_1char()){ case '!': /* !! last command */ if((p = last_cmd) != NULL){ c = in_1char(); break; } return(OK); case '*': if((p = last_cmd) == NULL) return(OK); if(!(p = skipsp(p))){ add_char('!' | mmask); add_char('*' | mmask); return(OK); } if(next_object(tbuf, &p, (char *)0, TRUE) == COMMENT) p = ""; c = in_1char(); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '-': /* !2 a numeric command */ p = tbuf; *p++ = c; while( (c = in_1char()) != EOF) if(c < '0' || c > '9') break; else *p++ = c; *p = 0; i = atoi(tbuf); if(i < 0) i = Curcnum - i; p = 0; /* is it in range */ if(i < Curcnum && i >= Curcnum - Hist_siz) p = History[i % Hist_siz]; if(p) break; add_char('!' | mmask); p = tbuf; while(*p) add_char(*p++ | mmask); if(c == EOF) return(EOF); Cur_ins->i_nleft++; /* push back last char */ Cur_ins->i_ptr--; return(OK); case '?': p = tbuf; while((c = in_1char()) != EOF){ if(index(IFS, c)) break; if(c == '?'){ c = in_1char(); break; } *p++ = c; } *p = 0; sstart = strlen(tbuf); if(sstart != 0) for(i = Hist_siz ; i >= 0 ; i--){ p = History[(Curcnum + i -1) % Hist_siz]; if(p == 0) continue; scar = strlen(p); for(q = p; q <= p + scar - sstart ; q++) if(strncmp(q, tbuf, sstart) == 0) goto found; } add_char('!' | mmask); p = tbuf; while(*p) add_char(*p++ | mmask); if(c == EOF) return(EOF); Cur_ins->i_nleft++; /* push back last char */ Cur_ins->i_ptr--; return(OK); case EOF: return(EOF); default: p = tbuf; do { if(index(IFS, c)) break; *p++ = c; } while((c = in_1char()) != EOF); *p = 0; sstart = strlen(tbuf); if(sstart == 0) i = -1; else for(i = Hist_siz ; i >= 0 ; i--){ p = History[(Curcnum + i -1) % Hist_siz]; if(p && strncmp(p, tbuf, sstart) == 0) goto found; } add_char('!' | mmask); p = tbuf; while(*p) add_char(*p++ | mmask); if(c == EOF) return(EOF); Cur_ins->i_nleft++; /* push back last char */ Cur_ins->i_ptr--; return(OK); } found:; /* * get here if found a valid string to put into the output * now check for editing chars */ if(c == EOF) return(EOF); hist_expand = TRUE; if(!index(":^$*-%", c)){ Cur_ins->i_nleft++; Cur_ins->i_ptr--; while(*p) add_char(*p++ | mmask); return(OK); } if(c == ':'){ c = in_1char(); if(c == EOF) return(EOF); } /* * char is a ':' operator * now find out what to do with it, p is the string that we have * from the history */ p = skipsp(p); if(!p) return(ERR); switch(c){ case '^': if(next_object(tbuf, &p, (char *)0, TRUE) == COMMENT) return(OK); if(!(p = skipsp(p))) return(OK); if(next_object(tbuf, &p, (char *)0, TRUE) == COMMENT) return(OK); p = tbuf; break; case '$': do { if(next_object(tbuf, &p, (char *)0, TRUE) == COMMENT) return(OK); } while(p = skipsp(p)); p = tbuf; break; case '*': if(next_object(tbuf, &p, (char *)0, TRUE) == COMMENT) return(OK); if(!(p = skipsp(p))) return(OK); break; case '-': break; case '%': break; case '0': if(next_object(tbuf, &p, (char *)0, TRUE) == COMMENT) return(OK); p = tbuf; break; default: if(c < '1' || c > '9'){ Cur_ins->i_nleft++; Cur_ins->i_ptr--; break; } } for(c = in_1char(); c == ':'; c = in_1char()){ switch(c = in_1char()){ case EOF: return(EOF); case 'h': break; } } if(c == EOF) return(EOF); while(*p) add_char(*p++ | mmask); return(OK); } /* * ^fred^frog^ processing */ get_bhist(mmask) { char match[128]; char repl[128]; char *p, *q; int c; int mlen, rlen, slen; for(p = match ; (c = in_1char()) != EOF ; *p++ =c) if(c == '^') break; if(c == EOF) return(EOF); *p = 0; for(p = repl ; (c = in_1char()) != EOF ; *p++ =c){ if(c == '^') break; if(index(IFS, c)) break; } if(c == EOF) return(EOF); *p = 0; if(c != '^'){ Cur_ins->i_nleft++; Cur_ins->i_ptr--; } if(last_cmd == 0) return(OK); slen = strlen(last_cmd); if((mlen = strlen(match)) == 0) return(OK); for(q = last_cmd ; q <= last_cmd + slen - mlen ; q++) if(strncmp(q, match, mlen) == 0){ for(p = last_cmd ; p < q ; p++) add_char(*p | mmask); for(p = repl ; *p ; p++) add_char(*p | mmask); for(p = q + mlen ; *p ; p++) add_char(*p | mmask); break; } return(OK); } /* * add the current command to the history list */ add_to_hist() { char **p; if(Cur_ins->i_fblk) /* if in loops don't do loops */ return; if(Hist_siz < 0){ if(last_cmd != NULL) free(last_cmd); last_cmd = strsave(skipsp(in_buf)); Curcnum++; return; } if( *(p = &History[Curcnum % Hist_siz]) != NULL) free(*p); last_cmd = *p = strsave(skipsp(in_buf)); Curcnum++; } /* * print out the history list */ do_hist(argc, argv) char **argv; { int i, j, k; char *p, *q; char *targs[5]; char tbuf[10]; if(argc != 1){ targs[0] = "set"; targs[1] = "history"; targs[2] = "="; targs[3] = argv[1]; targs[4] = 0; return(do_set(4, targs)); } if(Hist_siz < 0) return(OK); i = Curcnum; for(j = 0 ; j < Hist_siz ; j++, i++){ p = History[i % Hist_siz]; if(p != 0){ q = my_Itoa(i - Hist_siz); for(k = 6 - strlen(q) ; k >= 0 ; k--) tbuf[k] = ' '; strcpy(tbuf + 6 - strlen(q), q); put_s(tbuf); put_s(" "); put_s(p); put_s("\n"); } } return(OK); } /* * set the history length */ hist_set(val) { int i; char **xp; char **ohist; if(val < 0){ puterr("Cannot have negative history list.\n"); return(ERR); } if(val == Hist_siz) /* doesn't change history size - ok */ return(OK); if(History != 0){ /* delete old history list */ for(xp = History, i = 0 ; i < Hist_siz ; i++, xp++) if(*xp) free(*xp); free( (char *)History); History = 0; } Hist_siz = -1; if(val == 0) /* want's no history */ return(OK); History = (char **)mmalloc(sizeof(char *)*val); for(xp = History, i = 0; i < val ; i++, *xp++ = 0); Hist_siz = val; History[Curcnum % Hist_siz] = last_cmd; return(OK); }