/* See the file wizshell.c, wizshell.h or the files in docs/ for information */ #include "wizshell.h" /* HISTORY STUFF */ /* set_history_size * frees up history and reallocates * memory for new <size> */ void set_history_size(size) int size; { int i; char **temp; if ((temp=(char **) CALLOC(size,sizeof(char *)))==NULL) { ERROR("set_history_size","Could not allocate memory"); return; } for(i=0;i<envir.history_size; i++) FREE(*(envir.hist+i)); if(envir.hist) { fprintf(stdout,"History size set to: %d\n",size); FREE(envir.hist); } envir.history_size=size; envir.hist=temp; for(i=0; i<size; i++) /*MUSTDO make this variable.. not MAX_BUF */ if ((*(envir.hist+i)=(char *) CALLOC(MAX_BUF,sizeof(char)))==NULL) FATAL("history: Could not allocate memory"); envir.current_hist=0; } /* add_history * copies command and args in format: * <command><space><arg1><space><arg2>... * to current history location in history */ void add_history(comm) char **comm; { int a=0,b=0,c=0; char* here=*(envir.hist+envir.current_hist); while (comm[a]) { while (*(comm[a]+b) !='\0') { *(here+c)=*(comm[a]+b); b++; c++; } *(here+c)=' '; a++; b=0; c++; } *(here+c-1)='\0'; envir.current_hist++; if(envir.current_hist>=envir.history_size) envir.current_hist=0; envir.command_num++; } /* get_history * gets string added to history as command_num=num * returns NULL if num is outside history */ char *get_history(num) int num; { int hist_num; if(num<0) num+=envir.command_num; if(num<envir.command_num-envir.history_size) return NULL; if(num>=envir.command_num) return NULL; if(num<0) return NULL; hist_num=envir.current_hist-envir.command_num+num; if (hist_num<0) hist_num+=envir.history_size; return *(envir.hist+hist_num); } /* print_history * prints out strings in history array, * either starting at 0 or at the location * past current_history if the history has * wrapped around. */ void print_history() { int i=envir.current_hist; int c=envir.command_num-envir.history_size; if ((*(*(envir.hist+i))=='\0') || (i>envir.history_size-1)) { c=envir.command_num-envir.current_hist; i=0; } printf(" history [%d]\n",envir.history_size); while (c<envir.command_num) { printf(" %d %s\n",c,*(envir.hist+i)); i++; c++; if(i>envir.history_size-1) i=0; } } /* end HISTORY STUFF */ void do_set(comm) char **comm; { char *illegal[8]={"PATH","LOGNAME","SHELL","MAIL", "USER","WSHLOGIN","EDITOR","NETHOST"}; int ind=8; /* size of illegal */ char *tmp; if(!comm[2]) { if(tmp=getenv(comm[1])) { if(!strcmp(comm[1],"HOME")) fprintf(stderr,"/%s\n",tmp); else fprintf(stderr,"%s\n",tmp); } else fprintf(stderr,"setenv: Too few arguments.\n"); return; } if(!strcmp(comm[1],"prompt")) set_prompt(comm[2]); else if(!strcmp(comm[1],"debug")) { if(!strcmp(comm[2],"off")) DEBUGON=0; else DEBUGON=1; } else { for(ind--;ind>=0;ind--) if(!strncmp(comm[1],illegal[ind],strlen(illegal[ind]))) if(strlen(comm[1])<=strlen(illegal[ind]) || comm[1][strlen(illegal[ind])]=='=') { fprintf(stderr,"Illegal to set %s.\n",illegal[ind]); return; } MK_STR(tmp,strlen(comm[1])+strlen(comm[2])+2) strcpy(tmp,comm[1]); *(tmp+strlen(comm[1]))='='; if(!strcmp(comm[1],"HOME")) {/* HOME is special case */ if(comm[2][0]!='/') fprintf(stderr,"set: \"home\" must be an absolute path.\n"); else strcpy(tmp+strlen(comm[1])+1,comm[2]+1); } else strcpy(tmp+strlen(comm[1])+1,comm[2]); wshputenv(tmp); /* do not free a putenv */ } return; } /* ALIAS STUFF */ /* find an alias in a set */ alias_t *find_alias(name,set) char *name; alias_t *set; { while(set && strcmp(set->name,name)) set=set->next; /* if(set && strcmp(set->name,name)) return NULL; fprintf(stderr,"found: %s\n",set->name); */ return set; } /* do alias to set from line in form "name<whitespace>what<\0>" */ /* if no what, then just print the alias */ void do_alias(line,seth) char *line; alias_t **seth; { alias_t *tmp,*last,*new; char *str,*what,*endname,c; endname=line; while(*endname!=' ' && *endname!='\t' && *endname!='\0') endname++; c=*endname; *endname='\0'; what=endname; if(c!='\0') what=eat_white(what+1); if(*what=='\0') { tmp=find_alias(line,*seth); if(tmp && !strcmp(tmp->name,line)) fprintf(stderr,"%s\n",tmp->what); return; } /* i like being able to alias "alias" ;-) */ if(!strcmp(line,"unalias") /* || !strcmp(line,"alias") */ ) { fprintf(stderr,"%s: Too dangerous to alias that.\n",line); return; } tmp=*seth; last=NULL; while(tmp && strcmp(tmp->name,line)<0) { last=tmp; tmp=tmp->next; } /* add alias */ if(tmp && !strcmp(tmp->name,line)) FREE(tmp->what); else { if((tmp=(alias_t *) MALLOC(sizeof(alias_t)))==NULL) FATAL("Could not allocate alias memory") MK_STR(tmp->name,strlen(line)+1) strcpy(tmp->name,line); if(!last) { /* put at front */ tmp->next=*seth; *seth=tmp; } else { tmp->next=last->next; last->next=tmp; } } MK_STR(tmp->what,strlen(what)+1) strcpy(tmp->what,what); *endname=c; return; } /* end ALIAS STUFF */ /* replaces * look for things to replace in line string before converting to comm array * !<bangs>, aliases, $environment vars, ^lastline^change * also, converts \! to ! (non history bang) and ignores after # */ #define LOOP 40 /* number of aliases to eval before assuming alias loop */ char *replaces(line) char *line; { int i,j,a,aliasloop=0,tmpint,end,hist,env,caught,firstword=1; char buf[40],lastalias[40],*tmp,*tmp2,*tmp3; alias_t *aliastmp; line=eat_white(line); end=0; caught=0; i=end-1; while(line[++i]!='\0' && line[i]!='#' && line[i]!='\r' && line[i]!='\n') if(line[i]=='$' || line[i]=='!' || (!isspace(line[i]) && firstword)) { hist=(line[i]=='!'); env=(line[i]=='$'); if((hist || env) && i>0 && line[i-1]=='\\') { strcpy(line+i-1,line+i); /* change \! to ! and ignore */ end=i+1; /* skip $ or ! next time */ continue; } end=i; j=0; if(!hist && !env) while(line[i]!=' ' && line[i]!='\t' && line[i]!='\0' && line[i]!='\n') buf[j++]=line[i++]; else while(line[++i]!='/' && line[i]!=' ' && line[i]!='\t' && line[i]!='\0' && line[i]!='\'' && line[i]!='"' && line[i]!='`' && line[i]!='\n' && line[i]!='[' && line[i]!=']' && line[i]!=':') buf[j++]=line[i]; buf[j]='\0'; if(env) tmp=getenv(buf); else if(hist) { /* bang */ if(sscanf(buf,"%d",&tmpint)==1) tmp=get_history(tmpint); else { if(buf[0]=='\0') { i--; continue; } if(buf[0]=='!' && buf[1]=='\0') buf[0]='\0'; tmpint=envir.command_num-1; a=1; while(a && (tmp=get_history(tmpint))) { a=strlen(buf)-1; while(tmp[a]==buf[a] && a-->0); a++; tmpint--; } } } else { /* not env or hist, so check for alias */ /* catch simple alias loop (alias ls ls -s) */ if(strcmp(lastalias,buf) && (aliastmp=find_alias(buf,aliases))) { tmp=aliastmp->what; strcpy(lastalias,buf); } else { firstword=0; i=i-j-1; /* start at next char of first word (j=strlen(buf)) */ continue; } } if(!tmp || (!env && !hist && aliasloop++>LOOP)) { if(hist) fprintf(stderr,"%s: Event not found.\n",buf); else if(env) fprintf(stderr,"%s: Undefined variable.\n",buf); else fprintf(stderr,"Alias loop.\n"); if(caught) FREE(line); MK_STR(line,2) line[0]='\0'; return line; /* error, take no action */ } MK_STR(tmp2,end+strlen(line)-i+strlen(tmp)+1) strncpy(tmp2,line,end); if(env && !strcmp(buf,"HOME")) /* $HOME is special case.. */ *(tmp2+(end++))='/'; /* wsh needs / but programs don't */ strcpy(tmp2+end,tmp); strcpy(tmp2+end+strlen(tmp),line+i); if(caught) FREE(line); line=tmp2; caught=1; if(!hist && !env) i=-1; /* start at beginning again */ else i=i-strlen(buf)-2; /* start at beginning of replacement */ } /* done with search/replace in line for $ and ! and aliases */ /* while(line[i]!='\n' && line[i]!='\r' && line[i]!='\0') i++;*/ line[i]='\0'; if(!caught) return 0; return line; } /* catchline * catch some stuff before converting to comm array * now just 'alias' 'chat' and 'tell' * returns 1 if caught (add to history) */ int catchline(line) char *line; { char *endword,c,*tmp; alias_t *altmp; who_t *tw; FILE *fp; line=eat_white(line); endword=line; while(*endword!=' ' && *endword!='\t' && *endword!='\0') endword++; c=*endword; *endword='\0'; if(!strcmp(line,"alias")) { *endword=c; tmp=eat_white(endword); if(*tmp=='\0') { altmp=aliases; while(altmp) { fprintf(stderr,"%s\t%s\n",altmp->name,altmp->what); altmp=altmp->next; } return 1; } do_alias(tmp,&aliases); return 1; } if(!strcmp(line,"chat")) { *endword=c; chat(eat_white(endword)); return 1; } if(!strcmp(line,"tell")) { *endword=c; tell(eat_white(endword)); return 1; } *endword=c; return 0; } /* catchcomm * catch commands that don't get execvp'd * exit, logout, history stuff * other environment sets can go here * returns 0 if not caught * returns -1 if caught & quit * returns 1 if caught and add to history * returns 2 if caught, don't add to history */ int catchcomm(comm,interactive) char **comm; int interactive; { char *tmp; who_t *tw; FILE *fp; int tmpint; if (!strcmp(comm[0],"acc")) { print_acc(write_acc,0); print_acc(read_acc,0); return 1; } if (!strcmp(comm[0],"cd")) { cWD(comm[1],interactive && !envir.prompt2); return 1; } if (!strcmp(comm[0],"exit")) { if(!comm[1]) return -1; ERROR("exit","Expression syntax") return 1; } if (!strcmp(comm[0],"history")) { if (!comm[1]) { print_history(); return 1; } if(sscanf(comm[1],"%d",&tmpint)==1) set_history_size(tmpint); else fprintf(stderr,"%s: Badly formed number.\n",comm[1]); return 1; } if (!strcmp(comm[0],"logout")) { if(!comm[1]) return -1; ERROR("logout","Too many arguments") return 1; } if (!strcmp(comm[0],"pwd")) { if(comm[1]) fprintf(stderr,"usage: pwd\n"); else if(*WD) fprintf(stderr,"%s\n",WD); else fprintf(stderr,"/\n"); return 1; } if (!strcmp(comm[0],"mesg")) { if(!comm[1]) { /* this is the ugly mesg format, I didn't make it up */ if(envir.mesg) fprintf(stdout,"is y\n"); else fprintf(stdout,"is n\n"); return 1; } if((comm[1][0]=='y' || comm[1][0]=='n') && comm[1][1]=='\0') { envir.mesg=(comm[1][0]=='y'); read_utmp(1); /* read the utmp, change our entry and write back */ return 1; } fprintf(stderr,"usage: mesg [y] [n]\n"); return 1; } if(!strcmp(comm[0],"whoami")) { fprintf(stderr,"%s\n",getenv("WSHLOGIN")); return 1; } if(!strcmp(comm[0],"who")) { free_who(print_utmp(read_utmp(0),comm[1])); return 1; } if(!strcmp(comm[0],"setenv")) { if(!comm[1]) { char **env; for(env=environ;*env;env++) fprintf(stderr,"%s\n",*env); } else do_set(comm); return 1; } if(!strcmp(comm[0],"source") || !strcmp(comm[0],".")) { tmpint=source(comm[1],1); if(tmpint==1) fprintf(stderr,"%s: No such file or directory\n",comm[1]); if(tmpint==-1) fprintf(stderr,"%s: Permission denied\n",comm[1]); return 1; } if(!strcmp(comm[0],"unalias")) { if(comm[1]) { alias_t *tmp,*last; tmp=aliases; last=NULL; while(tmp && strcmp(tmp->name,comm[1])<0) { last=tmp; tmp=tmp->next; } if(!tmp) return 1; if(!last) /* we know that it must be the first */ aliases=aliases->next; else last->next=tmp->next; FREE(tmp); return 1; } ERROR("unalias","Too few arguments") return 1; } if(!strcmp(comm[0],"version")) { fprintf(stdout,"This is the WizShell (wsh) version: %s\n\n",VERSION); fprintf(stdout,"The wsh is part of the WizPort package\n" "Author: David Ljung\n" " (608) 257-COWS\n" " ljung@cae.wisc.edu\n"); return 1; } return 0; }