void readcommandDOS(char * const str, int maxlen) { union REGPACK r; assert(str); assert(maxlen); iobuf[0] = (maxlen < CMD_SIZE)? maxlen: CMD_SIZE; if(iobuf[1] > iobuf[0]) iobuf[1] = iobuf[0]; dprintf(("[CMDINPUT characters max:%u in:%u]\n", iobuf[0], iobuf[1])); if(echo) printprompt(); r.r_ax = 0xa00; r.r_ds = FP_SEG(iobuf); r.r_dx = FP_OFF(iobuf); intr(0x21, &r); dprintf(("[CMDINPUT characters max:%u out:%u]\n", iobuf[0], iobuf[1])); if(iobuf[1]) /* could bug if == 0 */ memcpy(str, &iobuf[2], iobuf[1]); str[iobuf[1]] = 0; outc('\n'); }
int main() { char line[MAXLINE]; path *pth = createpath(""); while (1) { programlist *pgl; if (printprompt() == -1) { fprintf(stderr, "Getting current directory failed.\n"); } fgets(line, MAXLINE, stdin); pgl = parseline(line, pth); int child; if(handleexit(pgl) == 0){ cleanuppgl(pgl); exit(0); } if (handlechdir(pgl) <= 0){ cleanuppgl(pgl); continue; } else if (handlepath(pgl, pth) <= 0) { cleanuppgl(pgl); continue; } child = fork(); if (child == 0) { execline(pgl, pth); /*printf("executed line\n"); */ cleanuppgl(pgl); exit(0); } else { int status; int waitret; while (1) { waitret = wait(&status); /* printf("wait ret = %d\n", waitret); */ if (waitret == -1 && errno == ECHILD) { break; } else if (waitret == -1 && errno != ECHILD) { fprintf(stderr, "Wait failed\n"); break; } } cleanuppgl(pgl); } } return 0; }
void sh_pk_ctrl_l(t_usent *us) { while (INDEX < us->c_size) { go_right(us); INDEX++; } while (us->curs_line != 0 || us->curs_col != us->prompt_size) { go_left(us); tputs(tgetstr("dc", NULL), 0, tputchar); INDEX--; } free(us->edit); if (!(us->edit = (char*)malloc(sizeof(char) * 255))) sh_error_quit("malloc us->edit fail"); ft_memset(us->edit, '\0', 255); tputs(tgetstr("cl", NULL), 0, tputchar); printprompt(NULL); }
void childhandler(int signal) { int status,i; pid_t pid; if (signal==SIGCHLD) {// sleep(0); while((pid=waitpid(-1, &status,WNOHANG))> 0) { //printf("\n"); for(i=0;i<back_index;i++) { if((back_job[i].pro_id)==pid) { back_job[i].back_active=0; // printf("zeroed: %d %d\n",back_job[i].pro_id,back_job[i].back_active); break; } } if(WIFEXITED(status)) { printf("\n%s with pid %d terminated with exit status: ",back_job[i].processname,pid); printf("%d\n",WEXITSTATUS(status)); } else { if(WIFSIGNALED(status)) { if(over_mark!=1) printf("\n%s with pid %d exited due to the signal no. %d\n",back_job[i].processname ,pid,WTERMSIG(status)); } } printprompt(); } } }
int main(void) { int res,ret; char cmd[MAXCMD]; struct cmdlist cmds; struct rlimit r; r.rlim_cur = 50; r.rlim_max = 10000; setrlimit(RLIMIT_FSIZE,&r); /* setting up the initial values of the structure */ /* this should be done every time when new object is created */ setupnewcommand(&cmds); /* Setting up file size limit for this process and for the child processes */ /* main loop of the shell */ /* this loop proceses command wirtten by user in the following steps: */ /* 1. Displaying command prompt 2. Reading command from the std input 3. Parsing this command 4. Executing parsed commands 5. Dealocating used memory */ while(1){ printprompt(); if(readcmd(cmd, MAXCMD) == RESERROR) continue; res = parsecmd(cmd, MAXCMD, &cmds); printparsedcmds(&cmds); ret = executecmds(&cmds); dealocate(&cmds); } return 0; }
int main(int argc, char *argv[]) { //struct rusage usage; int status,i,l,j,ii,length,l1,l2,controld,start,end,bpid; char *input_str; char c; int internal=0; int job_no; char **ncomms; char **args_copy; char prompt[1000]; char user[100],host[100]; pid_t pid; controld=0; //createsignal(); shell_pgid=getpid(); if (setpgid (shell_pgid, shell_pgid) < 0) { perror ("Couldn't put the shell in its own process group"); exit (1); } // handle sigint with hello signal(SIGINT, SIG_IGN); if(getcwd(home, sizeof(home))!=NULL) { while(1) { position=0; backexit=0; // back_index=0; flag=0; // printf("<prachi@LenovoG500s"); if(controld==0) printprompt(); controld=0; for(i=0;i<1000;i++) prompt[i]='\0'; if(getcwd(prompt, sizeof(prompt))!=NULL) { input_str=get_input(); if(input_str[0]!='\0') {i=0; ncomms=split_input3(input_str,1); position=ind; while(position--) { // printf("pid: %d\n",shell_pgid); internal=0; // args contains the "pipe" parsed commands args=split_input3(ncomms[i],2); if(args[0]!="\0"); { // check for built in commands if(args[0][0]=='c' && args[0][1]=='d') internal=1; else if(args[0][0]=='e' && args[0][1]=='x' && args[0][2]=='i' && args[0][3]=='t') internal=1; else if(args[0][0]=='e' && args[0][1]=='c' && args[0][2]=='h' && args[0][3]=='o') internal=1; else if(args[0][0]=='p' && args[0][1]=='w' && args[0][2]=='d') internal=1; else if(args[0][0]=='q' && args[0][1]=='u' && args[0][2]=='i' && args[0][3]=='t') internal=1; else if(args[0][0]=='f' && args[0][1]=='g') { // printf("fg\n"); internal=-1; } if(internal!=1 && internal!=-1) { int len; len=strlen(args[0]); if(args[0][len-1]=='&') back_mark=1; pid=fork(); if(pid==0) loop_pipe(args); else if(pid<0) perror("myshell"); else { if(back_mark!=1) waitpid(pid,&status, WUNTRACED); else { signal(SIGCHLD, childhandler); strcpy(copy,args[0]); len=strlen(copy); copy[len-1]='\0'; strcpy(back_job[back_index].processname,copy); // printf("args: %s",args[0]); back_job[back_index].pro_id=pid; back_job[back_index].back_active=1; back_index++; back_mark=0; // storing background processes data(pid , name) into an array printf("%d\n",pid); } } } else if(internal==1) { args=split_input2(args[0]); // if built-in commands execute_internal(flag); } else if(internal==-1) { // execute fg pid_t fpid; int status; args=split_input2(args[0]); fpid = execute_fg(atoi(args[1])); // printf("fpid: %d\n",fpid); if(fpid>0) { kill(fpid, SIGCONT); waitpid(fpid,&status,WCONTINUED); } } } i++; } free(input_str); free(args); } else controld=1; } else perror("myshell:"); } } else { perror("myshell:"); return EXIT_SUCCESS; } return 0; }
/* * do the prompt/input/process loop * * If xflg is true, the function will not go interactive, but returns. * If commandline != NULL, this command is processed first. * * Return: 0: on success */ int process_input(int xflag, char *commandline) { /* Dimensionate parsedline that no sprintf() can overflow the buffer */ char parsedline[MAX_INTERNAL_COMMAND_SIZE + sizeof(errorlevel) * 8] , *readline; /* Return the maximum pointer into parsedline to add 'numbytes' bytes */ #define parsedMax(numbytes) \ (parsedline + MAX_INTERNAL_COMMAND_SIZE - 1 - (numbytes)) char *evar; char *tp; char *ip; char *cp; char forvar; int echothisline; int tracethisline; do { interactive_command = 0; /* not directly entered by user */ echothisline = tracethisline = 0; if(commandline) { ip = commandline; readline = commandline = NULL; } else { if ((readline = malloc(MAX_INTERNAL_COMMAND_SIZE + 1)) == NULL) { error_out_of_memory(); return 1; } if (NULL == (ip = readbatchline(&echothisline, readline, MAX_INTERNAL_COMMAND_SIZE))) { /* if no batch input then... */ if (xflag /* must not go interactive */ || (fdattr(0) & 0x84) == 0x84 /* input is NUL device */ || feof(stdin)) /* no further input */ { free(readline); break; } /* Go Interactive */ interactive_command = 1; /* directly entered by user */ readcommand(ip = readline, MAX_INTERNAL_COMMAND_SIZE); tracemode = 0; /* reset trace mode */ } } /* * The question mark '?' has a double meaning: * C:\> ? * ==> Display short help * * C:\> ? command arguments * ==> enable tracemode for just this line */ if(*(ip = trim(ip)) == '?') { ip = trim(ip + 1); if(!*ip) { /* is short help command */ #ifdef INCLUDE_CMD_QUESTION showcmds(ip); #endif free(readline); continue; } /* this-line-tracemode */ echothisline = 0; tracethisline = 1; } /* The FOR hack If the line matches /^\s*for\s+\%[a-z]\s/, the FOR hack becomes active, because FOR requires the sequence "%<ch>" in its input. When the percent (%) expansion is made later on, any sequence "%<ch>" is retained. */ cp = ip; if(matchtok(cp, "for") && *cp == '%' && isalpha(cp[1]) && isspace(cp[2])) /* activate FOR hack */ forvar = toupper(cp[1]); else forvar = 0; cp = parsedline; while (*ip) { /* Assume that at least one character is added, place the test here to simplify the switch() statement */ if(cp >= parsedMax(1)) { cp = NULL; /* error condition */ break; } if (*ip == '%') { switch (*++ip) { case '\0': /* FOR hack forvar == 0 if no FOR is active */ *cp++ = '%'; break; case '%': *cp++ = *ip++; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (NULL != (tp = find_arg(*ip - '0'))) { if(cp >= parsedMax(strlen(tp))) { cp = NULL; goto intBufOver; } cp = stpcpy(cp, tp); ip++; } else *cp++ = '%'; /* Let the digit be copied in the cycle */ break; case '?': /* overflow check: parsedline has that many character "on reserve" */ cp += sprintf(cp, "%u", errorlevel); ip++; break; default: if(forvar == toupper(*ip)) { /* FOR hack */ *cp++ = '%'; /* let the var be copied in next cycle */ break; } if ((tp = strchr(ip, '%')) != NULL) { *tp = '\0'; if ((evar = getEnv(ip)) != NULL) { if(cp >= parsedMax(strlen(evar))) { cp = NULL; goto intBufOver; } cp = stpcpy(cp, evar); } ip = tp + 1; } break; } continue; } if (iscntrl(*ip)) *cp = ' '; else *cp++ = *ip++; } intBufOver: free(readline); if(!cp) { /* internal buffer overflow */ error_line_too_long(); continue; } *cp = '\0'; /* terminate copied string */ if (echothisline) /* Echo batch file line */ { printprompt(); puts(parsedline); } if (*parsedline) { if(tracethisline) ++tracemode; parsecommandline(parsedline); if(tracethisline) --tracemode; if (echothisline || echo) putchar('\n'); } } while (!canexit || !exitflag); return 0; }
/* read in a command line */ void readcommandEnhanced(char * const str, const int maxlen) { unsigned char insert = 1; unsigned ch; #ifdef FEATURE_FILENAME_COMPLETION unsigned lastch = 0; #endif #ifdef FEATURE_HISTORY int histLevel = 0; char prvLine[MAX_INTERNAL_COMMAND_SIZE]; #endif unsigned curx; unsigned cury; int count; unsigned current = 0; unsigned charcount = 0; assert(str); assert(maxlen <= MAX_INTERNAL_COMMAND_SIZE); /* if echo off, don't print prompt */ if(echo) printprompt(); orgx = wherex(); orgy = wherey(); memset(str, 0, maxlen); _setcursortype(_NORMALCURSOR); #ifdef FEATURE_HISTORY histGet(histLevel - 1, prvLine, sizeof(prvLine)); #endif do { ch = cgetchar(); if(cbreak) ch = KEY_CTL_C; switch(ch) { case KEY_BS: /* delete character to left of cursor */ if(current > 0 && charcount > 0) { if(current == charcount) { /* if at end of line */ str[current - 1] = 0; if (wherex() != 1) outs("\b \b"); else { goxy(MAX_X, wherey() - 1); outblank(); goxy(MAX_X, wherey() - 1); } } else { for (count = current - 1; count < charcount; count++) str[count] = str[count + 1]; if (wherex() != 1) goxy(wherex() - 1, wherey()); else goxy(MAX_X, wherey() - 1); curx = wherex(); cury = wherey(); outsblank(&str[current - 1]); goxy(curx, cury); } charcount--; current--; } break; case KEY_INSERT: /* toggle insert/overstrike mode */ insert ^= 1; if (insert) _setcursortype(_NORMALCURSOR); else _setcursortype(_SOLIDCURSOR); break; case KEY_DELETE: /* delete character under cursor */ if (current != charcount && charcount > 0) { for (count = current; count < charcount; count++) str[count] = str[count + 1]; charcount--; curx = wherex(); cury = wherey(); outsblank(&str[current]); goxy(curx, cury); } break; case KEY_HOME: /* goto beginning of string */ if (current != 0) { goxy(orgx, orgy); current = 0; } break; case KEY_END: /* goto end of string */ if (current != charcount) { goxy(orgx, orgy); outs(str); current = charcount; } break; #ifdef FEATURE_FILENAME_COMPLETION case KEY_TAB: /* expand current file name */ if(current == charcount) { /* only works at end of line */ if(lastch != KEY_TAB) { /* if first TAB, complete filename */ complete_filename(str, charcount); charcount = strlen(str); current = charcount; goxy(orgx, orgy); outs(str); if ((strlen(str) > (MAX_X - orgx)) && (orgy == MAX_Y + 1)) orgy--; } else { /* if second TAB, list matches */ if (show_completion_matches(str, charcount)) { printprompt(); orgx = wherex(); orgy = wherey(); outs(str); } } } else beep(); break; #endif case KEY_ENTER: /* end input, return to main */ #ifdef FEATURE_HISTORY if(str[0]) histSet(0, str); /* add to the history */ #endif outc('\n'); break; case KEY_CTL_C: /* ^C */ case KEY_ESC: /* clear str Make this callable! */ clrcmdline(str, maxlen, orgx, orgy); current = charcount = 0; if(ch == KEY_CTL_C && !echo) { /* enable echo to let user know that's this is the command line */ echo = 1; printprompt(); } break; case KEY_RIGHT: /* move cursor right */ if (current != charcount) { current++; if (wherex() == MAX_X) goxy(1, wherey() + 1); else goxy(wherex() + 1, wherey()); break; } /* cursor-right at end of string grabs the next character from the previous line */ /* FALL THROUGH */ #ifndef FEATURE_HISTORY break; #else case KEY_F1: /* get character from last command buffer */ if (current < strlen(prvLine)) { outc(str[current] = prvLine[current]); charcount = ++current; } break; case KEY_F3: /* get previous command from buffer */ if(charcount < strlen(prvLine)) { outs(strcpy(&str[charcount], &prvLine[charcount])); current = charcount = strlen(str); } break; case KEY_UP: /* get previous command from buffer */ if(!histGet(--histLevel, prvLine, sizeof(prvLine))) ++histLevel; /* failed -> keep current command line */ else { clrcmdline(str, maxlen, orgx, orgy); strcpy(str, prvLine); current = charcount = strlen(str); outs(str); histGet(histLevel - 1, prvLine, sizeof(prvLine)); } break; case KEY_DOWN: /* get next command from buffer */ if(histLevel) { clrcmdline(str, maxlen, orgx, orgy); strcpy(prvLine, str); histGet(++histLevel, str, maxlen); current = charcount = strlen(str); outs(str); } break; case KEY_F5: /* keep cmdline in F3/UP buffer and move to next line */ strcpy(prvLine, str); clrcmdline(str, maxlen, orgx, orgy); outc('@'); if(orgy >= MAX_Y) { outc('\n'); /* Force scroll */ orgy = MAX_Y; } else { ++orgy; } goxy(orgx, orgy); current = charcount = 0; break; #endif case KEY_LEFT: /* move cursor left */ if(current > 0) { current--; if (wherex() == 1) goxy(MAX_X, wherey() - 1); else goxy(wherex() - 1, wherey()); } break; case KEY_CTRL_LEFT: /* move cursor left to begin of word */ while(current > 0) { current--; if (wherex() == 1) goxy(MAX_X, wherey() - 1); else goxy(wherex() - 1, wherey()); if(isworddelimiter(str[current-1]) /* ignore current == 0 */ && !isworddelimiter(str[current])) break; } break; case KEY_CTRL_RIGHT: /* move cursor right to begin of word */ while(current < charcount) { current++; if (wherex() == MAX_X) goxy(1, wherey() + 1); else goxy(wherex() + 1, wherey()); if(isworddelimiter(str[current-1]) && !isworddelimiter(str[current])) break; } break; default: /* insert character into string... */ if ((ch >= 32 && ch <= 255) && (charcount != (maxlen - 2))) { if (insert && current != charcount) { for (count = charcount; count > current; count--) str[count] = str[count - 1]; str[current++] = ch; curx = wherex() + 1; cury = wherey(); outs(&str[current - 1]); if ((strlen(str) > (MAX_X - orgx)) && (orgy == MAX_Y + 1)) cury--; goxy(curx, cury); charcount++; } else { if (current == charcount) charcount++; str[current++] = ch; outc(ch); } if ((strlen(str) > (MAX_X - orgx)) && (orgy == MAX_Y + 1)) orgy--; } else beep(); break; } #ifdef FEATURE_FILENAME_COMPLETION lastch = ch; #endif } while(ch != KEY_ENTER); _setcursortype(_NORMALCURSOR); }
/* * do the prompt/input/process loop * * If xflg is true, the function will not go interactive, but returns. * If commandline != NULL, this command is processed first. * * Return: 0: on success */ int process_input(int xflag, char *commandline) { /* Dimensionate parsedline that no sprintf() can overflow the buffer */ char parsedline[MAX_INTERNAL_COMMAND_SIZE + sizeof(errorlevel) * 8] , *readline; #if 0 /* Return the maximum pointer into parsedline to add 'numbytes' bytes */ #define parsedMax(numbytes) \ (parsedline + MAX_INTERNAL_COMMAND_SIZE - 1 - (numbytes)) char *evar; char *tp; char *cp; #endif char *ip; #if 0 char forvar; #endif int echothisline; int tracethisline; do { #ifdef FEATURE_LONG_FILENAMES if( toupper( *getEnv( "LFN" ) ) == 'N' ) __supportlfns = 0; else __supportlfns = 1; #endif interactive_command = 0; /* not directly entered by user */ echothisline = tracethisline = 0; if(commandline) { ip = commandline; readline = commandline = 0; } else { if ((readline = malloc(MAX_INTERNAL_COMMAND_SIZE + 1)) == 0) { error_out_of_memory(); return 1; } if (0 == (ip = readbatchline(&echothisline, readline, MAX_INTERNAL_COMMAND_SIZE))) { /* if no batch input then... */ if (xflag /* must not go interactive */ || (fdattr(0) & 0x84) == 0x84 /* input is NUL device */ || feof(stdin)) /* no further input */ { free(readline); break; } /* Go Interactive */ interactive_command = 1; /* directly entered by user */ /* Ensure the prompt starts at column #0 */ if(echo && (mywherex()>1)) outc('\n'); readcommand(ip = readline, MAX_INTERNAL_COMMAND_SIZE); tracemode = 0; /* reset trace mode */ } } /* Make sure there is no left-over from last run */ currCmdHelpScreen = 0; /* * The question mark '?' has a double meaning: * C:\> ? * ==> Display short help * * C:\> ? command arguments * ==> enable tracemode for just this line */ if(*(ip = ltrimcl(ip)) == '?') { ip = ltrimcl(ip + 1); if(!*ip) { /* is short help command */ #ifdef INCLUDE_CMD_QUESTION showcmds(ip); #endif free(readline); continue; } /* this-line-tracemode */ echothisline = 0; tracethisline = 1; } #if 0 /* The FOR hack If the line matches /^\s*for\s+\%[a-z]\s/, the FOR hack becomes active, because FOR requires the sequence "%<ch>" in its input. When the percent (%) expansion is made later on, any sequence "%<ch>" is retained. */ cp = ip; if(matchtok(cp, "for") && *cp == '%' && isalpha(cp[1]) && isargdelim(cp[2])) /* activate FOR hack */ forvar = toupper(cp[1]); else forvar = 0; #else if(cmd_for_hackery(ip)) { free(readline); continue; } #endif { int rc = expandEnvVars(ip, parsedline); free(readline); if(!rc) { error_line_too_long(); continue; } } if (echothisline) /* Echo batch file line */ { printprompt(); puts(parsedline); } if (*parsedline) { if(swapOnExec != ERROR) swapOnExec = defaultToSwap; if(tracethisline) ++tracemode; parsecommandline(parsedline, TRUE); if(tracethisline) --tracemode; } } while (!canexit || !exitflag); return 0; }
/* * process the command line and execute the appropriate functions * full input/output redirection and piping are supported */ void parsecommandline(char *s, int redirect) { char *in = 0; char *out = 0; char *fname0 = 0; char *fname1 = 0; char *nextcmd; int of_attrib = O_CREAT | O_TRUNC | O_WRONLY; int num; assert(s); dprintf(("[parsecommandline (%s)]\n", s)); #ifdef FEATURE_ALIASES aliasexpand(s, MAX_INTERNAL_COMMAND_SIZE); dprintf(("[alias expanded to (%s)]\n", s)); #endif if (tracemode) { /* Question after the variables expansion and make sure _all_ executed commands will honor the trace mode */ /* * Commands may be nested ("if errorlevel 1 echo done>test"). To * prevent redirecting FreeCOM prompts to user file, temporarily * revert redirection. */ int redir_fdin, redir_fdout, answer; if (oldinfd != -1) { redir_fdin = dup (0); dup2 (oldinfd, 0); } if (oldoutfd != -1) { redir_fdout = dup (1); dup2 (oldoutfd, 1); } printprompt(); outs(s); /* If the user hits ^Break, it has the same effect as usually: If he is in a batch file, he is asked if to abort all the batchfiles or just the current one */ answer = userprompt(PROMPT_YES_NO); if (oldinfd != -1) { dup2 (redir_fdin, 0); dos_close (redir_fdin); } if (oldoutfd != -1) { dup2 (redir_fdout, 1); dos_close (redir_fdout); } if (answer != 1) return; /* "No" or ^Break */ } if(!redirect) { docommand(s); return; } assert(oldinfd == -1); /* if fails something is wrong; should NEVER */ assert(oldoutfd == -1); /* happen! -- 2000/01/13 ska*/ num = get_redirection(s, &in, &out, &of_attrib); if (num < 0) /* error */ goto abort; /* Set up the initial conditions ... */ if (in || (num > 1)) /* Need to preserve stdin */ oldinfd = dup(0); if (in) /* redirect input from this file name */ { dos_close(0); if (0 != devopen(in, O_RDONLY)) { error_redirect_from_file(in); goto abort; } } if (out || (num > 1)) /* Need to preserve stdout */ oldoutfd = dup(1); /* Now do all but the last pipe command */ while (num-- > 1) { dos_close(1); /* Close current output file */ if ((fname0 = tmpfn()) == 0) goto abort; dos_creat(fname0, 0); nextcmd = s + strlen(s) + 1; docommand(s); dos_close(1); dup2(oldoutfd, 1); dos_close(0); killtmpfn(fname1); /* fname1 can by NULL */ fname1 = fname0; fname0 = 0; dos_open(fname1, O_RDONLY); s = nextcmd; } /* Now set up the end conditions... */ if (out) /* Final output to here */ { dos_close(1); if (1 != devopen(out, of_attrib)) { error_redirect_to_file(out); goto abort; } } else if (oldoutfd != -1) /* Restore original stdout */ { dos_close(1); dup2(oldoutfd, 1); dos_close(oldoutfd); oldoutfd = -1; } docommand(s); /* process final command */ abort: if (oldinfd != -1) /* Restore original STDIN */ { dos_close(0); dup2(oldinfd, 0); dos_close(oldinfd); oldinfd = -1; } if (oldoutfd != -1) /* Restore original STDOUT */ { dos_close(1); dup2(oldoutfd, 1); dos_close(oldoutfd); oldoutfd = -1; } killtmpfn(fname1); killtmpfn(fname0); if (out) free(out); if (in) free(in); }
/* CCRETVAL */ int Inputl(void) { CCRETVAL retval; KEYCMD cmdnum = 0; unsigned char tch; /* the place where read() goes */ Char ch; int num; /* how many chars we have read at NL */ int expnum; struct varent *crct = inheredoc ? NULL : adrof(STRcorrect); struct varent *autol = adrof(STRautolist); struct varent *matchbeep = adrof(STRmatchbeep); struct varent *imode = adrof(STRinputmode); Char *SaveChar, *CorrChar; int matchval; /* from tenematch() */ int nr_history_exp; /* number of (attempted) history expansions */ COMMAND fn; int curlen = 0; int newlen; int idx; Char *autoexpand; if (!MapsAreInited) /* double extra just in case */ ed_InitMaps(); ClearDisp(); /* reset the display stuff */ ResetInLine(0); /* reset the input pointers */ if (GettingInput) MacroLvl = -1; /* editor was interrupted during input */ if (imode && imode->vec != NULL) { if (!Strcmp(*(imode->vec), STRinsert)) inputmode = MODE_INSERT; else if (!Strcmp(*(imode->vec), STRoverwrite)) inputmode = MODE_REPLACE; } #if defined(FIONREAD) && !defined(OREO) if (!Tty_raw_mode && MacroLvl < 0) { # ifdef SUNOS4 long chrs = 0; # else /* !SUNOS4 */ /* * *Everyone* else has an int, but SunOS wants long! * This breaks where int != long (alpha) */ int chrs = 0; # endif /* SUNOS4 */ (void) ioctl(SHIN, FIONREAD, (ioctl_t) & chrs); if (chrs == 0) { if (Rawmode() < 0) return 0; } } #endif /* FIONREAD && !OREO */ GettingInput = 1; NeedsRedraw = 0; tellwhat = 0; if (RestoreSaved) { copyn(InputBuf, SavedBuf.s, INBUFSIZE);/*FIXBUF*/ LastChar = InputBuf + LastSaved; Cursor = InputBuf + CursSaved; Hist_num = HistSaved; HistSaved = 0; RestoreSaved = 0; } if (HistSaved) { Hist_num = HistSaved; GetHistLine(); HistSaved = 0; } if (Expand) { (void) e_up_hist(0); Expand = 0; } Refresh(); /* print the prompt */ for (num = OKCMD; num == OKCMD;) { /* while still editing this line */ #ifdef DEBUG_EDIT if (Cursor > LastChar) xprintf("Cursor > LastChar\r\n"); if (Cursor < InputBuf) xprintf("Cursor < InputBuf\r\n"); if (Cursor > InputLim) xprintf("Cursor > InputLim\r\n"); if (LastChar > InputLim) xprintf("LastChar > InputLim\r\n"); if (InputLim != &InputBuf[INBUFSIZE - 2])/*FIXBUF*/ xprintf("InputLim != &InputBuf[INBUFSIZE-2]\r\n"); if ((!DoingArg) && (Argument != 1)) xprintf("(!DoingArg) && (Argument != 1)\r\n"); if (CcKeyMap[0] == 0) xprintf("CcKeyMap[0] == 0 (maybe not inited)\r\n"); #endif /* if EOF or error */ if ((num = GetNextCommand(&cmdnum, &ch)) != OKCMD) { break; } if (cmdnum >= NumFuns) {/* BUG CHECK command */ #ifdef DEBUG_EDIT xprintf(CGETS(6, 1, "ERROR: illegal command from key 0%o\r\n"), ch); #endif continue; /* try again */ } /* now do the real command */ retval = (*CcFuncTbl[cmdnum]) (ch); /* save the last command here */ LastCmd = cmdnum; /* make sure fn is initialized */ fn = (retval == CC_COMPLETE_ALL) ? LIST_ALL : LIST; /* use any return value */ switch (retval) { case CC_REFRESH: Refresh(); /*FALLTHROUGH*/ case CC_NORM: /* normal char */ Argument = 1; DoingArg = 0; /*FALLTHROUGH*/ case CC_ARGHACK: /* Suggested by Rich Salz */ /* <*****@*****.**> */ curchoice = -1; curlen = (int) (LastChar - InputBuf); break; /* keep going... */ case CC_EOF: /* end of file typed */ curchoice = -1; curlen = (int) (LastChar - InputBuf); num = 0; break; case CC_WHICH: /* tell what this command does */ tellwhat = 1; *LastChar++ = '\n'; /* for the benifit of CSH */ num = (int) (LastChar - InputBuf); /* number characters read */ break; case CC_NEWLINE: /* normal end of line */ curlen = 0; curchoice = -1; matchval = 1; if (crct && crct->vec != NULL && (!Strcmp(*(crct->vec), STRcmd) || !Strcmp(*(crct->vec), STRall))) { Char *Origin; PastBottom(); Origin = Strsave(InputBuf); cleanup_push(Origin, xfree); SaveChar = LastChar; if (SpellLine(!Strcmp(*(crct->vec), STRcmd)) == 1) { Char *Change; PastBottom(); Change = Strsave(InputBuf); cleanup_push(Change, xfree); *Strchr(Change, '\n') = '\0'; CorrChar = LastChar; /* Save the corrected end */ LastChar = InputBuf; /* Null the current line */ SoundBeep(); printprompt(2, short2str(Change)); cleanup_until(Change); Refresh(); if (xread(SHIN, &tch, 1) < 0) { #ifdef convex /* * need to print error message in case file * is migrated */ if (errno) stderror(ERR_SYSTEM, progname, strerror(errno)); #else cleanup_until(Origin); break; #endif } ch = tch; if (ch == 'y' || ch == ' ') { LastChar = CorrChar; /* Restore the corrected end */ xprintf("%s", CGETS(6, 2, "yes\n")); } else { Strcpy(InputBuf, Origin); LastChar = SaveChar; if (ch == 'e') { xprintf("%s", CGETS(6, 3, "edit\n")); *LastChar-- = '\0'; Cursor = LastChar; printprompt(3, NULL); ClearLines(); ClearDisp(); Refresh(); cleanup_until(Origin); break; } else if (ch == 'a') { xprintf("%s", CGETS(6, 4, "abort\n")); LastChar = InputBuf; /* Null the current line */ Cursor = LastChar; printprompt(0, NULL); Refresh(); cleanup_until(Origin); break; } xprintf("%s", CGETS(6, 5, "no\n")); } flush(); } cleanup_until(Origin); } else if (crct && crct->vec != NULL && !Strcmp(*(crct->vec), STRcomplete)) { if (LastChar > InputBuf && LastChar[-1] == '\n') { LastChar[-1] = '\0'; LastChar--; Cursor = LastChar; } match_unique_match = 1; /* match unique matches */ matchval = CompleteLine(); match_unique_match = 0; curlen = (int) (LastChar - InputBuf); if (matchval != 1) { PastBottom(); } if (matchval == 0) { xprintf("%s", CGETS(6, 6, "No matching command\n")); } else if (matchval == 2) { xprintf("%s", CGETS(6, 7, "Ambiguous command\n")); } if (NeedsRedraw) { ClearLines(); ClearDisp(); NeedsRedraw = 0; } Refresh(); Argument = 1; DoingArg = 0; if (matchval == 1) { PastBottom(); *LastChar++ = '\n'; *LastChar = '\0'; } curlen = (int) (LastChar - InputBuf); } else PastBottom(); if (matchval == 1) { tellwhat = 0; /* just in case */ Hist_num = 0; /* for the history commands */ /* return the number of chars read */ num = (int) (LastChar - InputBuf); /* * For continuation lines, we set the prompt to prompt 2 */ printprompt(1, NULL); } break; case CC_CORRECT: if (tenematch(InputBuf, Cursor - InputBuf, SPELL) < 0) SoundBeep(); /* Beep = No match/ambiguous */ curlen = Repair(); break; case CC_CORRECT_L: if (SpellLine(FALSE) < 0) SoundBeep(); /* Beep = No match/ambiguous */ curlen = Repair(); break; case CC_COMPLETE: case CC_COMPLETE_ALL: case CC_COMPLETE_FWD: case CC_COMPLETE_BACK: switch (retval) { case CC_COMPLETE: fn = RECOGNIZE; curlen = (int) (LastChar - InputBuf); curchoice = -1; rotate = 0; break; case CC_COMPLETE_ALL: fn = RECOGNIZE_ALL; curlen = (int) (LastChar - InputBuf); curchoice = -1; rotate = 0; break; case CC_COMPLETE_FWD: fn = RECOGNIZE_SCROLL; curchoice++; rotate = 1; break; case CC_COMPLETE_BACK: fn = RECOGNIZE_SCROLL; curchoice--; rotate = 1; break; default: abort(); } if (InputBuf[curlen] && rotate) { newlen = (int) (LastChar - InputBuf); for (idx = (int) (Cursor - InputBuf); idx <= newlen; idx++) InputBuf[idx - newlen + curlen] = InputBuf[idx]; LastChar = InputBuf + curlen; Cursor = Cursor - newlen + curlen; } curlen = (int) (LastChar - InputBuf); nr_history_exp = 0; autoexpand = varval(STRautoexpand); if (autoexpand != STRNULL) nr_history_exp += ExpandHistory(); /* try normal expansion only if no history references were found */ if (nr_history_exp == 0 || Strcmp(autoexpand, STRonlyhistory) != 0) { /* * Modified by Martin Boyer ([email protected]): * A separate variable now controls beeping after * completion, independently of autolisting. */ expnum = (int) (Cursor - InputBuf); switch (matchval = tenematch(InputBuf, Cursor-InputBuf, fn)){ case 1: if (non_unique_match && matchbeep && matchbeep->vec != NULL && (Strcmp(*(matchbeep->vec), STRnotunique) == 0)) SoundBeep(); break; case 0: if (matchbeep && matchbeep->vec != NULL) { if (Strcmp(*(matchbeep->vec), STRnomatch) == 0 || Strcmp(*(matchbeep->vec), STRambiguous) == 0 || Strcmp(*(matchbeep->vec), STRnotunique) == 0) SoundBeep(); } else SoundBeep(); break; default: if (matchval < 0) { /* Error from tenematch */ curchoice = -1; SoundBeep(); break; } if (matchbeep && matchbeep->vec != NULL) { if ((Strcmp(*(matchbeep->vec), STRambiguous) == 0 || Strcmp(*(matchbeep->vec), STRnotunique) == 0)) SoundBeep(); } else SoundBeep(); /* * Addition by David C Lawrence <*****@*****.**>: If an * attempted completion is ambiguous, list the choices. * (PWP: this is the best feature addition to tcsh I have * seen in many months.) */ if (autol && autol->vec != NULL && (Strcmp(*(autol->vec), STRambiguous) != 0 || expnum == Cursor - InputBuf)) { if (adrof(STRhighlight) && MarkIsSet) { /* clear highlighting before showing completions */ MarkIsSet = 0; ClearLines(); ClearDisp(); Refresh(); MarkIsSet = 1; } PastBottom(); fn = (retval == CC_COMPLETE_ALL) ? LIST_ALL : LIST; (void) tenematch(InputBuf, Cursor-InputBuf, fn); } break; } } if (NeedsRedraw) { PastBottom(); ClearLines(); ClearDisp(); NeedsRedraw = 0; } Refresh(); Argument = 1; DoingArg = 0; break; case CC_LIST_CHOICES: case CC_LIST_ALL: if (InputBuf[curlen] && rotate) { newlen = (int) (LastChar - InputBuf); for (idx = (int) (Cursor - InputBuf); idx <= newlen; idx++) InputBuf[idx - newlen + curlen] = InputBuf[idx]; LastChar = InputBuf + curlen; Cursor = Cursor - newlen + curlen; } curlen = (int) (LastChar - InputBuf); if (curchoice >= 0) curchoice--; fn = (retval == CC_LIST_ALL) ? LIST_ALL : LIST; /* should catch ^C here... */ if (tenematch(InputBuf, Cursor - InputBuf, fn) < 0) SoundBeep(); Refresh(); Argument = 1; DoingArg = 0; break; case CC_LIST_GLOB: if (tenematch(InputBuf, Cursor - InputBuf, GLOB) < 0) SoundBeep(); curlen = Repair(); break; case CC_EXPAND_GLOB: if (tenematch(InputBuf, Cursor - InputBuf, GLOB_EXPAND) <= 0) SoundBeep(); /* Beep = No match */ curlen = Repair(); break; case CC_NORMALIZE_PATH: if (tenematch(InputBuf, Cursor - InputBuf, PATH_NORMALIZE) <= 0) SoundBeep(); /* Beep = No match */ curlen = Repair(); break; case CC_EXPAND_VARS: if (tenematch(InputBuf, Cursor - InputBuf, VARS_EXPAND) <= 0) SoundBeep(); /* Beep = No match */ curlen = Repair(); break; case CC_NORMALIZE_COMMAND: if (tenematch(InputBuf, Cursor - InputBuf, COMMAND_NORMALIZE) <= 0) SoundBeep(); /* Beep = No match */ curlen = Repair(); break; case CC_HELPME: xputchar('\n'); /* should catch ^C here... */ (void) tenematch(InputBuf, LastChar - InputBuf, PRINT_HELP); Refresh(); Argument = 1; DoingArg = 0; curchoice = -1; curlen = (int) (LastChar - InputBuf); break; case CC_FATAL: /* fatal error, reset to known state */ #ifdef DEBUG_EDIT xprintf(CGETS(7, 8, "*** editor fatal ERROR ***\r\n\n")); #endif /* DEBUG_EDIT */ /* put (real) cursor in a known place */ ClearDisp(); /* reset the display stuff */ ResetInLine(1); /* reset the input pointers */ Refresh(); /* print the prompt again */ Argument = 1; DoingArg = 0; curchoice = -1; curlen = (int) (LastChar - InputBuf); break; case CC_ERROR: default: /* functions we don't know about */ if (adrof(STRhighlight)) { ClearLines(); ClearDisp(); Refresh(); } DoingArg = 0; Argument = 1; SoundBeep(); flush(); curchoice = -1; curlen = (int) (LastChar - InputBuf); break; } } (void) Cookedmode(); /* make sure the tty is set up correctly */ GettingInput = 0; flush(); /* flush any buffered output */ return num; }
void browse(const char *ipath, const char *ifilter) { int r, fd; regex_t re; char *newpath; struct stat sb; char *name, *bin, *dir, *tmp, *run, *env; int nowtyping = 0; FILE *fp; oldpath = NULL; path = xstrdup(ipath); fltr = xstrdup(ifilter); begin: /* Path and filter should be malloc(3)-ed strings at all times */ r = populate(); if (r == -1) { if (!nowtyping) { printwarn(); goto nochange; } } for (;;) { redraw(); /* Handle filter-as-you-type mode */ if (nowtyping) goto moretyping; nochange: switch (nextsel(&run, &env)) { case SEL_QUIT: free(path); free(fltr); dentfree(dents, n); return; case SEL_BACK: /* There is no going back */ if (strcmp(path, "/") == 0 || strcmp(path, ".") == 0 || strchr(path, '/') == NULL) goto nochange; dir = xdirname(path); if (canopendir(dir) == 0) { free(dir); printwarn(); goto nochange; } /* Save history */ oldpath = path; path = dir; /* Reset filter */ free(fltr); fltr = xstrdup(ifilter); goto begin; case SEL_GOIN: /* Cannot descend in empty directories */ if (n == 0) goto nochange; name = dents[cur].name; newpath = mkpath(path, name); DPRINTF_S(newpath); /* Get path info */ fd = open(newpath, O_RDONLY | O_NONBLOCK); if (fd == -1) { printwarn(); free(newpath); goto nochange; } r = fstat(fd, &sb); if (r == -1) { printwarn(); close(fd); free(newpath); goto nochange; } close(fd); DPRINTF_U(sb.st_mode); switch (sb.st_mode & S_IFMT) { case S_IFDIR: if (canopendir(newpath) == 0) { printwarn(); free(newpath); goto nochange; } free(path); path = newpath; /* Reset filter */ free(fltr); fltr = xstrdup(ifilter); goto begin; case S_IFREG: bin = openwith(newpath); if (bin == NULL) { printmsg("No association"); free(newpath); goto nochange; } exitcurses(); spawn(bin, newpath, NULL); initcurses(); free(newpath); continue; default: printmsg("Unsupported file"); goto nochange; } case SEL_FLTR: /* Read filter */ printprompt("filter: "); tmp = readln(); if (tmp == NULL) tmp = xstrdup(ifilter); /* Check and report regex errors */ r = setfilter(&re, tmp); if (r != 0) { free(tmp); goto nochange; } free(fltr); fltr = tmp; DPRINTF_S(fltr); /* Save current */ if (n > 0) oldpath = mkpath(path, dents[cur].name); goto begin; case SEL_TYPE: nowtyping = 1; tmp = NULL; moretyping: printprompt("type: "); if (tmp != NULL) printw("%s", tmp); r = readmore(&tmp); DPRINTF_D(r); DPRINTF_S(tmp); if (r == 1) nowtyping = 0; /* Check regex errors */ if (tmp != NULL) { r = setfilter(&re, tmp); if (r != 0) if (nowtyping) { goto moretyping; } else { free(tmp); goto nochange; } } /* Copy or reset filter */ free(fltr); if (tmp != NULL) fltr = xstrdup(tmp); else fltr = xstrdup(ifilter); /* Save current */ if (n > 0) oldpath = mkpath(path, dents[cur].name); if (!nowtyping) free(tmp); goto begin; case SEL_NEXT: if (cur < n - 1) cur++; break; case SEL_PREV: if (cur > 0) cur--; break; case SEL_PGDN: if (cur < n - 1) cur += MIN((LINES - 4) / 2, n - 1 - cur); break; case SEL_PGUP: if (cur > 0) cur -= MIN((LINES - 4) / 2, cur); break; case SEL_HOME: cur = 0; break; case SEL_END: cur = n - 1; break; case SEL_CD: /* Read target dir */ printprompt("chdir: "); tmp = readln(); if (tmp == NULL) { clearprompt(); goto nochange; } newpath = mkpath(path, tmp); free(tmp); if (canopendir(newpath) == 0) { free(newpath); printwarn(); goto nochange; } free(path); path = newpath; free(fltr); fltr = xstrdup(ifilter); /* Reset filter */ DPRINTF_S(path); goto begin; case SEL_MTIME: mtimeorder = !mtimeorder; /* Save current */ if (n > 0) oldpath = mkpath(path, dents[cur].name); goto begin; case SEL_REDRAW: /* Save current */ if (n > 0) oldpath = mkpath(path, dents[cur].name); goto begin; case SEL_RUN: run = xgetenv(env, run); exitcurses(); spawn(run, NULL, path); initcurses(); break; case SEL_RUNARG: name = dents[cur].name; run = xgetenv(env, run); exitcurses(); spawn(run, name, path); initcurses(); break; case SEL_PRINT: name = dents[cur].name; fp = fopen("savelist.txt", "a"); fprintf(fp, "%s/%s\n", path, name); fclose(fp); break; } /* Screensaver */ if (idletimeout != 0 && idle == idletimeout) { idle = 0; exitcurses(); spawn(idlecmd, NULL, NULL); initcurses(); } } }