#include #include #include #include #include #include #include #include #include #include #include #include #include "Ctree.h" #include "defs.h" #include "fsmsubs.h" extern FSMarg *_TMPIFSM_getarg(void); extern FSMarg *_TMPRFSM_getarg(void); static int didinit = 0; static TREE *tree; static const char *prompt; static char *buf; static int len; static int in_dquote; static int dquoteplace; static int do_return; static int ungotten; static sigset_t allsigs; static sigset_t catchsigs; static char *sigscaught; static struct sigaction *oldsigs; static IND_CHAIN *input; static const char *shell; static struct termios old_state; static struct termios new_state; static void (*put_char_fxn)(char) = 0; static int (*get_char_fxn)(FILE *) = 0; static char *whole_line = 0; static I_F num; static I_F min; static I_F max; static double factor; static int sign; static int exp_sign; static int exponent; static const char *numterm; extern FILE *C_match_fp; FILE *C_match_fp; static unsigned int flags = 0; #define FLAG(name) (flags&CTREE_F_##name) #if 0 tree_match_catch_sig(do_catch,dont_catch) int do_catch; int dont_catch; { catchsigs = (catchsigs & ~ dont_catch) | do_catch; } tree_match_save_whole_line(where) char *where; { whole_line = where; } #endif void tree_match_set_get_routine(int (*fxn)(FILE *)) { get_char_fxn = fxn; } void tree_match_set_put_routine(void (*fxn)(char)) { put_char_fxn = fxn; } void _TMPI_init(void) { sign = 0; } void _TMPI_negative(void) { sign = 1; } void _TMPI_value(int v) { num.i = sign ? -v : v; } void _TMPR_init(void) { factor = 1; num.f = 0; sign = 1; exp_sign = 1; exponent = 0; } void _TMPR_negative(void) { sign = -1; } void _TMPR_negate_exp(void) { exp_sign = -1; } void _TMPR_set_exp(int n) { exponent = n; } void _TMPR_int_digit(char d) { num.f *= 10; num.f += d - '0'; } void _TMPR_frac_digit(char d) { num.f += (d-'0') * (factor /= 10); } void _TMPR_finish_real(void) { num.f *= sign; exponent *= exp_sign; while (exponent < 0) { num.f /= 10; exponent ++; } while (exponent > 0) { num.f *= 10; exponent --; } } FILE *tree_match_input_stream(void) { return(input?input->file:0); } unsigned int *tree_match_flags(void) { return(&flags); } static void fixup_input(int dosigs) { sigset_t mask; if (dosigs) { sigemptyset(&mask); sigprocmask(SIG_BLOCK,&allsigs,&mask); } tcsetattr(0,TCSANOW|TCSASOFT,&old_state); if (dosigs) sigprocmask(SIG_SETMASK,&mask,0); } static void done(void) __attribute__((__noreturn__)); static void done(void) { fixup_input(1); exit(0); } static int get_char(void) { int c; IND_CHAIN *icp; if (ungotten >= 0) { c = ungotten; ungotten = -1; return(c); } if (input == 0) done(); if (! put_char_fxn) fflush(stdout); if (get_char_fxn) { c = (*get_char_fxn)(input->file); } else { c = getc(input->file); } while (input && (c == EOF)) { if (input->file != stdin) fclose(input->file); icp = input->link; free(input); input = icp; if (input) { C_match_fp = input->file; if (get_char_fxn) { c = (*get_char_fxn)(input->file); } else { c = getc(input->file); } } } if (input == 0) return(-1); return(c); } static void put_char(char c) { if (put_char_fxn) (*put_char_fxn)(c); else putchar(c); } static int print(const char *, ...) __attribute__((__format__(__printf__,1,2))); static int print(const char *fmt, ...) { va_list ap; FILE *f; int n; static int w(void *cookie __attribute__((__unused__)), const char *buf, int len) { int i; for (i=0;ilink = 0; input->file = stdin; C_match_fp = stdin; shell = getenv("SHELL"); if (shell == 0) shell = "/bin/sh"; } if (tcgetattr(0,&old_state) < 0) return; new_state = old_state; new_state.c_lflag &= ~(ICANON|ECHOKE|ECHOE|ECHO|ECHONL|ECHOPRT|ECHOCTL); new_state.c_cc[VMIN] = 1; new_state.c_cc[VTIME] = 0; tcsetattr(0,TCSANOW|TCSASOFT,&new_state); if (dosigs) sigprocmask(SIG_SETMASK,&prevmask,0); } static void uncatch_signals(void) { int i; for (i=1;istring; return(rv); } static int is_real(char *s) { return(_TMPRFSM_(s)); } static int is_hex(const char *s) { num.i = 0; while (1) { numterm = s; switch (*s) { case '0': num.i <<= 4; break; case '1': num.i = (num.i << 4) + 1; break; case '2': num.i = (num.i << 4) + 2; break; case '3': num.i = (num.i << 4) + 3; break; case '4': num.i = (num.i << 4) + 4; break; case '5': num.i = (num.i << 4) + 5; break; case '6': num.i = (num.i << 4) + 6; break; case '7': num.i = (num.i << 4) + 7; break; case '8': num.i = (num.i << 4) + 8; break; case '9': num.i = (num.i << 4) + 9; break; case 'a': case 'A': num.i = (num.i << 4) + 10; break; case 'b': case 'B': num.i = (num.i << 4) + 11; break; case 'c': case 'C': num.i = (num.i << 4) + 12; break; case 'd': case 'D': num.i = (num.i << 4) + 13; break; case 'e': case 'E': num.i = (num.i << 4) + 14; break; case 'f': case 'F': num.i = (num.i << 4) + 15; break; default: return(!*s); break; } } } static int is_oct(const char *s) { num.i = 0; while (1) { numterm = s; switch (*s) { case '0': num.i <<= 3; break; case '1': num.i = (num.i << 3) + 1; break; case '2': num.i = (num.i << 3) + 2; break; case '3': num.i = (num.i << 3) + 3; break; case '4': num.i = (num.i << 3) + 4; break; case '5': num.i = (num.i << 3) + 5; break; case '6': num.i = (num.i << 3) + 6; break; case '7': num.i = (num.i << 3) + 7; break; default: return(!*s); break; } } } static void traverse_load(void) { TREE *t; char *cp; char *sp; char *to; KEY *k; int cond; t = tree; cp = to = buf; while (1) { if (*cp == '"') { sp = index(cp+1,'"'); if (sp != 0) sp ++; } else { sp = index(cp,' '); } if (sp == 0) { to[-1] = '\0'; return; } *sp = '\0'; for (k=t->keys;k;k=k->link) { switch (k->type) { case KEY_NORMAL: cond = (strcmp(k->name,cp) == 0); break; case KEY_I: cond = is_int(cp); break; case KEY_X: cond = is_hex(cp); break; case KEY_O: cond = is_oct(cp); break; case KEY_R: case KEY_D: cond = is_real(cp); break; case KEY_Q: case KEY_S: cond = 1; break; case KEY_V: cond = (strcmp(k->valp,cp) == 0); break; } if (cond) break; } switch (k->type) { case KEY_I: case KEY_X: case KEY_O: *(int *)k->valp = num.i; break; case KEY_R: *(float *)k->valp = num.f; break; case KEY_D: *(double *)k->valp = num.f; break; case KEY_Q: case KEY_S: { int isquoted; isquoted = (*cp == '"'); if (isquoted) { cp ++; sp[-1] = '\0'; } strcpy((char *)k->valp,cp); if (isquoted) { cp --; sp[-1] = '"'; } } break; default: while ((*to++ = *cp++)) ; to[-1] = ' '; break; } *sp = ' '; cp = sp + 1; t = k->subtree; } } static int Read(int fd, void *data, int len) { char *dp; int tot; int did; dp = data; tot = 0; while (len > 0) { did = read(fd,dp,len); if (did < 0) return(-1); if (did == 0) break; dp += did; len -= did; tot += did; } return(tot); } static void do_delete(void) { if (len > 0) { len --; if (in_dquote && (len < dquoteplace)) in_dquote = 0; print("\b \b"); } } static void do_control_r(void) { print("^R\n"); do_redraw(); } static void do_control_u(void) { while (len > 0) { len --; print("\b \b"); } in_dquote = 0; } static void do_control_g(void) { put_char('\a'); } static void do_command_char(char c) { switch (c) { case '\b': case '\177': do_delete(); break; case '\n': fixup_input(1); { pid_t kid; int p[2]; pipe(p); kid = fork(); if (kid < 0) { print(" --- Cannot fork: %s\n",strerror(errno)); } else if (kid == 0) { int e; buf[len] = '\0'; setuid(getuid()); setgid(getgid()); close(p[0]); fcntl(p[1],F_SETFD,1); if (len == 1) { execl(shell,shell,0); } else { execl(shell,shell,"-c",buf+1,0); } e = errno; write(p[1],&e,sizeof(e)); _exit(0); } else { int status; int e; int dead; close(p[1]); switch (Read(p[0],&e,sizeof(int))) { case 0: put_char('\n'); dead = wait4(kid,&status,0,0); if (dead < 0) printf("wait4: %s\n",strerror(errno)); break; case sizeof(int): printf(" -- can't exec %s: %s\n",shell,strerror(e)); wait4(kid,&status,0,0); break; default: printf(" -- internal protocol error\n"); kill(kid,SIGTERM); wait4(kid,&status,0,0); break; } } len = 0; printf("%s",prompt); } init_input(1); break; case 'U' & 0x1f: case 'X' & 0x1f: do_control_u(); break; case 'R' & 0x1f: do_control_r(); break; default: if ((c >= ' ') && (c <= '~')) { buf[len++] = c; put_char(c); } else { do_control_g(); } break; } } static void do_indir_char(char c) { switch (c) { case '\b': case '\177': do_delete(); break; case ' ': case '\n': case '[' & 0x1f: { IND_CHAIN *icp; FILE *f; put_char('\n'); buf[len] = '\0'; f = fopen(buf+1,"r"); if (f == NULL) { print("Cannot open `%s'\n",buf+1); } else { icp = malloc(sizeof(IND_CHAIN)); icp->file = f; icp->link = input; input = icp; C_match_fp = input->file; } print("%s",prompt); len = 0; } break; case 'U' & 0x1f: case 'X' & 0x1f: do_control_u(); break; case 'R' & 0x1f: do_control_r(); break; default: if ((c >= ' ') && (c <= '~')) { buf[len++] = c; put_char(c); } else { do_control_g(); } break; } } static void do_comment_char(char c) { switch (c) { case '\b': case '\177': do_delete(); break; case 'U' & 0x1f: case 'X' & 0x1f: do_control_u(); break; case 'R' & 0x1f: do_control_r(); break; case '\n': put_char('\n'); len = 0; do_redraw(); break; default: if ((c >= ' ') && (c <= '~')) { buf[len++] = c; put_char(c); } else { do_control_g(); } break; } } static TREE *traverse(TREE **T, char **Cp) #define t (*T) #define cp (*Cp) { char *sp; KEY *k; int cond; while (1) { if (*cp == '"') { sp = index(cp+1,'"'); if (sp) sp ++; } else { sp = index(cp,' '); } if (! sp) return(t); *sp = '\0'; for (k=t->keys;k;k=k->link) { switch (k->type) { case KEY_NORMAL: cond = !strcmp(k->name,cp); break; case KEY_I: cond = is_int(cp); break; case KEY_X: cond = is_hex(cp); break; case KEY_O: cond = is_oct(cp); break; case KEY_R: case KEY_D: cond = is_real(cp); break; case KEY_Q: case KEY_S: cond = 1; break; case KEY_V: cond = !strcmp((char *)k->valp,cp); break; } if (cond) break; } if (! cond) return(0); *sp = ' '; cp = sp + 1; t = k->subtree; } } #undef t #undef cp static void do_dquote_char(char c) { switch (c) { case '\b': case '\177': do_delete(); break; case 'U' & 0x1f: case 'X' & 0x1f: do_control_u(); break; case 'R' & 0x1f: do_control_r(); break; case '\n': case '[' & 0x1f: case '"': { TREE *t; char *cp; KEY *k; t = tree; cp = buf; traverse(&t,&cp); for (k=t->keys;k;k=k->link) { if ( ( (k->type == KEY_Q) || (k->type == KEY_S) ) && ( !k->conditional || (*(int (*)(const char *))k->conditional)(cp) ) ) break; } if (k) { print("\" "); if (! k->subtree) do_return = 1; buf[len++] = '"'; buf[len++] = ' '; in_dquote = 0; } else { do_control_g(); while (in_dquote) do_delete(); } } break; default: if ((c >= ' ') && (c <= '~')) { buf[len++] = c; put_char(c); } else { do_control_g(); } break; } } static void get_min_max(KEY *k) { switch (k->type) { case KEY_I: case KEY_X: case KEY_O: min.i = k->flags.s.min_addr ? *k->min.ip : k->min.i; max.i = k->flags.s.max_addr ? *k->max.ip : k->max.i; break; case KEY_R: case KEY_D: min.f = k->flags.s.min_addr ? *k->min.fp : k->min.f; max.f = k->flags.s.max_addr ? *k->max.fp : k->max.f; break; } } static int print_key(KEY *k) { int nc; switch (k->type) { case KEY_NORMAL: print("%s",k->name); nc = strlen(k->name); break; case KEY_I: print("[integer"); nc = 8; get_min_max(k); if (k->flags.s.havemin) { if (k->flags.s.havemax) { nc += print(" %d to %d]",min.i,max.i); } else { nc += print(" >= %d]",min.i); } } else { if (k->flags.s.havemax) { nc += print(" <= %d]",max.i); } else { put_char(']'); nc ++; } } break; case KEY_X: print("[hex integer"); nc = 12; get_min_max(k); if (k->flags.s.havemin) { if (k->flags.s.havemax) { nc += print(" %x to %x]",min.i,max.i); } else { nc += print(" >= %x]",min.i); } } else { if (k->flags.s.havemax) { nc += print(" <= %x]",max.i); } else { put_char(']'); nc ++; } } break; case KEY_O: print("[octal integer"); nc = 14; get_min_max(k); if (k->flags.s.havemin) { if (k->flags.s.havemax) { nc += print(" %o to %o]",min.i,max.i); } else { nc += print(" >= %o]",min.i); } } else { if (k->flags.s.havemax) { nc += print(" <= %o]",max.i); } else { put_char(']'); nc ++; } } break; case KEY_R: case KEY_D: print("[real"); nc = 5; get_min_max(k); { if (k->flags.s.havemin) { if (k->flags.s.havemax) { nc += print(" %g to %g]",min.f,max.f); } else { nc += print(" >= %g]",min.f); } } else { if (k->flags.s.havemax) { nc += print(" <= %g]",max.f); } else { put_char(']'); nc ++; } } } break; case KEY_Q: case KEY_S: print("[string]"); nc = 8; break; case KEY_V: nc = print("%s",(char *)k->valp); break; } return(nc); } static int common_part(const char *s1, const char *s2) { int ri; for (ri=0;(s1[ri]==s2[ri])&&s1[ri];ri++) ; return(ri); } static void print_tree(TREE *t) { int printcol; static void print_keys(TREE *t, int indent) { KEY *k; for (k=t->keys;k;k=k->link) { while (printcol < indent) { put_char(' '); printcol ++; } printcol += print_key(k); if (k->subtree) { print_keys(k->subtree,printcol+1); } else { put_char('\n'); printcol = 0; } } } printcol = 0; print_keys(t,0); } static void do_normal_char(char c) { switch (c) { case '\b': case '\177': do_delete(); break; case '\n': case ' ': case '[' & 0x1f: { TREE *t; char *cp; KEY *k; KEY *exact; KEY *match; char *partstr; char *str; int count; int cond; int COND; int l; int max_match; int min_match; int match_part; t = tree; cp = buf; traverse(&t,&cp); l = strlen(cp); if (FLAG(DEBUG)) { char vbuf[5]; vis(&vbuf[0],c,VIS_CSTYLE|VIS_WHITE,'x'); print("\nafter traverse, l=%d c=%s cp=\"%s\"\n",l,&vbuf[0],cp); } if ((l == 0) && (c == '\n')) { put_char('\n'); do_redraw(); break; } exact = 0; count = 0; partstr = 0; max_match = -1; for (k=t->keys;k;k=k->link) { str = 0; if (FLAG(DEBUG)) { print("Key = "); print_key(k); } switch (k->type) { case KEY_NORMAL: str = k->name; cond = (strncmp(str,cp,l) == 0); COND = (strcmp(str,cp) == 0); match_part = common_part(str,cp); if ( cond && k->conditional && !(*(int (*)(const char *))k->conditional)(cp)) { cond = 0; COND = 0; match_part = 0; } break; case KEY_I: cond = 0; COND = is_int(cp); match_part = numterm - cp; if ( COND && k->conditional && !(*(int (*)(int))k->conditional)(num.i) ) { COND = 0; match_part = 0; } if (COND) { get_min_max(k); if ( (k->flags.s.havemin && (num.i < min.i)) || (k->flags.s.havemax && (num.i > max.i)) ) { COND = 0; match_part = 0; } } break; case KEY_X: cond = 0; COND = is_hex(cp); match_part = numterm - cp; if ( COND && k->conditional && !(*(int (*)(int))k->conditional)(num.i) ) { COND = 0; match_part = 0; } if (COND) { get_min_max(k); if ( (k->flags.s.havemin && (num.i < min.i)) || (k->flags.s.havemax && (num.i > max.i)) ) { COND = 0; match_part = 0; } } break; case KEY_O: cond = 0; COND = is_oct(cp); match_part = numterm - cp; if ( COND && k->conditional && !(*(int (*)(int))k->conditional)(num.i) ) { COND = 0; match_part = 0; } if (COND) { get_min_max(k); if ( (k->flags.s.havemin && (num.i < min.i)) || (k->flags.s.havemax && (num.i > max.i)) ) { COND = 0; match_part = 0; } } break; case KEY_R: case KEY_D: cond = 0; COND = is_real(cp); match_part = _TMPRFSM_getarg()->string - cp; if ( COND && k->conditional && !(*(int (*)(double))k->conditional)(num.f) ) { COND = 0; match_part = 0; } if (COND) { get_min_max(k); if ( (k->flags.s.havemin && (num.f < min.f)) || (k->flags.s.havemax && (num.f > max.f)) ) { COND = 0; match_part = 0; } } break; case KEY_Q: case KEY_S: cond = 0; COND = (l != 0); match_part = l; if ( COND && k->conditional && !(*(int (*)(const char *))k->conditional)(cp) ) { COND = 0; match_part = 0; } break; case KEY_V: str = (char *) k->valp; cond = (strncmp(str,cp,l) == 0); COND = (strcmp(str,cp) == 0); match_part = common_part(str,cp); if ( COND && k->conditional && !(*(int (*)(const char *))k->conditional)(cp) ) { cond = 0; COND = 0; match_part = 0; } break; } if (FLAG(DEBUG)) { print(" --> cond = %d, COND = %d, match_part = %d\n", cond,COND,match_part); } if (match_part > max_match) { max_match = match_part; } if (COND) { exact = k; } if (cond || COND) { int i; if (str) { if (partstr) { i = common_part(str,partstr); if (i < min_match) { min_match = i; } } else { min_match = strlen(partstr=str); } } count ++; match = k; } } if (exact != 0) { put_char(' '); buf[len++] = ' '; if (exact->subtree == 0) { do_return = 1; } } else { if (count == 0) { put_char('\a'); while (l > max_match) { print("\b \b"); l --; len --; } } else if (count == 1) { char *cp; cp = match->name + l; print("%s ",cp); while ((buf[len++] = *cp++)) ; buf[len-1] = ' '; if (match->subtree == 0) do_return = 1; } else if (l < min_match) { char *cp; int i; cp = partstr + l; i = min_match - l; print("%.*s",i,cp); for (;i;i--) buf[len++] = *cp++; } else { put_char('\a'); } } } break; case 'U' & 0x1f: case 'X' & 0x1f: do_control_u(); break; case 'R' & 0x1f: do_control_r(); break; case '?': { TREE *t = tree; char *cp = buf; char *str; KEY *k; int cond; int l; int col; int n_cols; int width; traverse(&t,&cp); if ( t->keys && (t->keys->link == 0) && (t->keys->type == KEY_Q) ) { buf[len++] = c; put_char(c); break; } put_char('\n'); l = strlen(cp); col = 1; width = 1; for (k=t->keys;k;k=k->link) { switch (k->type) { case KEY_NORMAL: str = k->name; cond = (strncmp(str,cp,l) == 0); break; case KEY_I: cond = 1; break; case KEY_X: cond = 1; break; case KEY_O: cond = 1; break; case KEY_R: case KEY_D: cond = 1; break; case KEY_Q: case KEY_S: cond = 1; break; case KEY_V: str = (char *) k->valp; cond = !strncmp(str,cp,l); break; } if (cond) { int l; k->flags.s.swept = 1; switch (k->type) { case KEY_NORMAL: l = strlen(k->name); if (k->conditional) l ++; if (width < l) width = l; break; case KEY_I: col = 0; break; case KEY_X: col = 0; break; case KEY_O: col = 0; break; case KEY_R: case KEY_D: col = 0; break; case KEY_Q: case KEY_S: col = 0; break; case KEY_V: l = strlen((char *)k->valp); if (k->conditional) l ++; if (width < l) width = l; break; } } else { k->flags.s.swept = 0; } } width += 2; if (col) { n_cols = (width > 79) ? 1 : 79/width; width = 79 / n_cols; } else { n_cols = 1; } col = 0; l = 0; for (k=t->keys;k;k=k->link) { if (k->flags.s.swept) { for (;l<(col*width);l++) put_char(' '); switch (k->type) { case KEY_NORMAL: l += print("%s%s",k->conditional?"?":"",k->name); break; case KEY_I: if (k->help) { print("%s\n",k->help); } else { print("A%s integer",k->conditional?" conditional":"n"); get_min_max(k); if (k->flags.s.havemin) { if (k->flags.s.havemax) { print(" %d to %d",min.i,max.i); } else { print(" not less than %d",min.i); } } else { if (k->flags.s.havemax) { print(" not more than %d",max.i); } } } break; case KEY_X: if (k->help) { print("%s\n",k->help); } else { print("A%s hex integer",k->conditional?" conditional":""); get_min_max(k); if (k->flags.s.havemin) { if (k->flags.s.havemax) { print(" %x to %x",min.i,max.i); } else { print(" not less than %x",min.i); } } else { if (k->flags.s.havemax) { print(" not more than %x",max.i); } } } break; case KEY_O: if (k->help) { print("%s\n",k->help); } else { print("A%s octal integer",k->conditional?" conditional":"n"); get_min_max(k); if (k->flags.s.havemin) { if (k->flags.s.havemax) { print(" %o to %o",min.i,max.i); } else { print(" not less than %o",min.i); } } else { if (k->flags.s.havemax) { print(" not more than %o",max.i); } } } break; case KEY_R: case KEY_D: if (k->help) { print("%s\n",k->help); } else { print("A%s real number",k->conditional?" conditional":""); get_min_max(k); if (k->flags.s.havemin) { if (k->flags.s.havemax) { print(" %g to %g",min.f,max.f); } else { print(" not less than %g",min.f); } } else { if (k->flags.s.havemax) { print(" not more than %g",max.f); } } } break; case KEY_Q: case KEY_S: if (k->help) { print("%s\n",k->help); } else { print("A%s string",k->conditional?" conditional":""); } break; case KEY_V: l += print("%s%s",k->conditional?"?":"",(char *)k->valp); break; } if (++col >= n_cols) { put_char('\n'); l = 0; col = 0; } } } if (col > 0) put_char('\n'); } do_redraw(); break; case '*': { TREE *t; char *cp; t = tree; cp = buf; traverse(&t,&cp); if ( t->keys && (t->keys->link == 0) && (t->keys->type == KEY_Q) ) { buf[len++] = c; put_char(c); break; } put_char('\n'); print_tree(t); } do_redraw(); break; case '"': { TREE *t; char *cp; int l; t = tree; cp = buf; traverse(&t,&cp); l = strlen(cp); if (l != 0) { buf[len++] = '"'; put_char('"'); break; } dquoteplace = len; buf[len++] = '"'; in_dquote = 1; put_char('"'); } break; default: if ((c >= ' ') && (c <= '~')) { buf[len++] = c; put_char(c); } else { do_control_g(); } break; } } void tree_match(void *Tree, const char *Prompt, char *Buf) { char c; sigset_t prevmask; tree = Tree; prompt = Prompt; buf = Buf; if (! didinit) doinit(); len = 0; do_return = 0; _TMP_current_tree = tree; push_back(-1); sigemptyset(&prevmask); sigprocmask(SIG_BLOCK,&allsigs,&prevmask); catch_signals(); sigprocmask(SIG_SETMASK,&prevmask,0); print("%s",prompt); init_input(1); in_dquote = 0; while (1) { c = get_char(); buf[len] = '\0'; switch (buf[0]) { case '!': do_command_char(c); break; case '@': do_indir_char(c); break; case '#': do_comment_char(c); break; default: if (in_dquote) { do_dquote_char(c); } else { do_normal_char(c); } break; } if (do_return) { sigset_t mask; buf[len] = '\0'; if (whole_line) strcpy(whole_line,buf); whole_line = 0; traverse_load(); put_char('\n'); sigprocmask(SIG_BLOCK,&allsigs,&mask); fixup_input(0); uncatch_signals(); sigprocmask(SIG_SETMASK,&mask,0); return; } } }