/* PHName: parse hname and return list of matching models */ static void PHName(ILink *models,HMMSet *hset) { if (trace & T_ITM) printf(" Models \n "); SkipSpaces(); if (ch == '(') { ReadCh(); PHIdent(models,hset); SkipSpaces(); while(ch == ',') { ReadCh(); PHIdent(models,hset); SkipSpaces(); } if (ch != ')') EdError(") expected"); ReadCh(); } else PHIdent(models,hset); if (trace & T_ITM) { printf("\n %d models in itemlist\n",NumItems(*models)); fflush(stdout); } }
/* ** Generator() reads characters from the input stream until a non- ** alphanumeric character is encountered. Only the first 127 characters ** are significant as generator name and are copied into the global ** array Gen[]. All other characters are discarded. */ static void Generator(void) { int i; for (i = 0; i < 127 && (isalnum(Ch) || Ch == '_' || Ch == '.'); i++) { Gen[i] = Ch; ReadCh(); } Gen[i] = '\0'; /* Discard the rest. */ while (isalnum(Ch) || Ch == '_' || Ch == '.') ReadCh(); }
/* ** SkipBlanks() skips the characters ' ', '\t' and '\n' as well as ** comments. A comment starts with '#' and finishes at the end of ** the line. */ static void SkipBlanks(void) { /* If Ch is empty, the next character is fetched. */ if (Ch == '\0') ReadCh(); /* First blank characters and comments are skipped. */ while (Ch == ' ' || Ch == '\t' || Ch == '\n' || Ch == '#') { if (Ch == '#') { /* Skip to the end of line. */ while (Ch != '\n') ReadCh(); } if (Ch == '\n') { Line++; Char = 0; } ReadCh(); } }
/* PItemSet: parse and item set appending items to ilist */ static void PItemSet(ILink *ilist, char *type, HMMSet *hset) { ILink models = NULL; /* list of hmms in item set */ ILink p; PHName(&models,hset); /* parse hname and get list of models */ SkipSpaces(); if (ch == '.') { /* look for subcomponents */ ReadCh(); switch (GetKey()) { case TRANSP_KEY: AddTransP(models,ilist,type); break; case STATE_KEY: PState(models,ilist,type,hset); break; default: EdError("State or TransP expected"); } FreeItems(&models); } else { /* append just the list of models to ilist */ ChkType('h',type); p = *ilist; if (p==NULL) *ilist = models; else { while (p->next != NULL) p = p->next; p->next = models; } } }
/* PState: parse state and add all matches in models to ilist */ static void PState(ILink models, ILink *ilist, char *type, HMMSet *hset) { IntSet states; int j; HMMDef *hmm; ILink h; states = CreateSet(maxStates); PIndex(states); SkipSpaces(); if (ch == '.') { ReadCh(); PStatecomp(models,ilist,type,states,hset); } else { ChkType('s',type); for (h=models; h!=NULL; h=h->next) { hmm = h->owner; for (j=2; j<hmm->numStates; j++) if (IsMember(states,j)) { /* tie ->info */ if (trace & T_ITM) printf(" %12s.state[%d]\n", HMMPhysName(hset,hmm),j); AddItem(hmm,hmm->svec+j,ilist); } } } FreeSet(states); }
/* PIndex: parse and index and return in s */ static void PIndex(IntSet s) { SkipSpaces(); if (ch != '[') EdError("[ expected"); ReadCh(); PIntRange(s); SkipSpaces(); while (ch==',') { ReadCh(); PIntRange(s); SkipSpaces(); } if (ch != ']') EdError("] expected"); ReadCh(); }
/* ** ReadCh() reads the next character from the current input file. ** At the same time it checks for lines terminated with '\'. Such ** a line is continued in the next line, therefore ReadCh() discards ** '\' and the following '\n'. */ static void ReadCh(void) { Ch = getc(InFp); Char++; if (Ch == '\\') { Ch = getc(InFp); if (Ch == '\n') { Line++; Char = 0; ReadCh(); } else { ungetc(Ch, InFp); Ch = '\\'; } } }
/* EXPORT->PItemList: parse items in item list setting ilist and type */ char *PItemList(ILink *ilist, char *type, HMMSet *hset, Source *s, Boolean itrace) { int rtrace; /* Initialise static variables */ rtrace=trace; if (itrace) trace|=T_ITM; source = s; maxMixes = MaxMixInSet(hset); maxStates = MaxStatesInSet(hset); position=pattern; *position=0; /* Parse item set */ ReadCh(); SkipSpaces(); if (ch != '{') EdError("{ expected"); ReadCh(); PItemSet(ilist,type,hset); SkipSpaces(); while (ch == ',') { ReadCh(); PItemSet(ilist,type,hset); SkipSpaces(); } if (ch != '}') EdError("} expected"); if (trace & T_ITM) fflush(stdout); trace=rtrace; return(pattern); }
/* PIntRange: parse an integer range and add its members to s */ static void PIntRange(IntSet s) { int i,i1,i2; i1 = GetInt(1,s.nMembers); SkipSpaces(); if (ch == '-') { ReadCh(); i2 = GetInt(1,s.nMembers); } else i2=i1; for (i=i1; i<=i2; i++) AddMember(s,i); }
/* ** Number reads a number from the input. */ static void Number(void) { unsigned int m, n = 0, overflow = 0; while (isdigit(Ch)) { m = n; n = 10 * n + (Ch - '0'); if ((n - (Ch - '0')) / 10 != m) { overflow = 1; break; } ReadCh(); } if (overflow) { fprintf(stderr, "Integer overflow reading %u%c", m, Ch); ReadCh(); while (isdigit(Ch)) { fprintf(stderr, "%c", Ch); ReadCh(); } fprintf(stderr, " in\n"); SyntaxError((char *)0); } else if (n >= (1U << (8 * sizeof(unsigned int) - 1))) { fprintf(stderr, "Integer overflow reading %u in\n", n); SyntaxError((char *)0); } N = n; }
/* GetInt: read integer coerced given range */ static int GetInt(int lo, int hi) { char buf[20]; int i = 0, num; SkipSpaces(); if (!isdigit(ch)) EdError("Int expected"); while (isdigit(ch)) { if (i==19) EdError("Integer too long!"); buf[i++] = ch; ReadCh(); } buf[i] = '\0'; num = atoi(buf); if (num<lo) num=lo; if (num>hi) num=hi; return num; }
/* GetKey: get a keyword */ static Keyword GetKey(void) { char buf[20]; int i = 0; Keyword k; SkipSpaces(); if (!isalpha(ch)) EdError("Keyword expected"); while (isalpha(ch)) { buf[i++] = toupper(ch); ReadCh(); if (i==20) EdError("Keyword too long!"); } buf[i] = '\0'; for (k=TRANSP_KEY; k<=COV_KEY; k=(Keyword) (k+1)) if (strcmp(keymap[k],buf) == 0 ) return k; EdError("Unknown Keyword"); return COV_KEY; /* never reached -- make compiler happy */ }
/* characters for unquoted strings */ static char *GetAlpha(char *s) { static char term[]=".,)}"; Boolean wasQuoted; int i,n,q; wasQuoted=FALSE; SkipSpaces(); if (ch == DBL_QUOTE || ch == SING_QUOTE){ wasQuoted = TRUE; q = ch; ReadCh(); } for (i=0; i<MAXSTRLEN ; i++){ if (wasQuoted){ if (ch == q) { ReadCh(); s[i] = '\0'; return s; } } else { if (isspace(ch) || strchr(term,ch)){ s[i] = '\0'; return s; } } if (ch==ESCAPE_CHAR) { ReadCh(); if (ch<'0' || ch>'7') { n = ch - '0'; ReadCh(); if (ch<'0' || ch>'7') EdError("Octal digit expected"); n = n*8 + ch - '0'; ReadCh(); if (ch<'0' || ch>'7') EdError("Octal digit expected"); ch += n*8 - '0'; } } s[i] = ch; ReadCh(); } EdError("String too long"); return NULL; /* never reached -- make compiler happy */ }
/* PStatecomp: parse a statecomp */ static void PStatecomp(ILink models, ILink *ilist, char *type, IntSet states, HMMSet *hset) { HMMDef *hmm; ILink h; int s,j; IntSet streams; Keyword kw; switch(kw=GetKey()) { case MIX_KEY: case STREAM_KEY: if (hset->hsKind==TIEDHS || hset->hsKind==DISCRETEHS) HError(7231,"PStatecomp: Cannot specify streams or mixes unless continuous"); streams = CreateSet(SMAX); if(kw==STREAM_KEY) { PIndex(streams); SkipSpaces(); if (ch != '.') EdError(". expected after stream spec"); ReadCh(); if (GetKey() != MIX_KEY) EdError("Mix expected after Stream index"); } else AddMember(streams,1); SkipSpaces(); if (ch=='[') PMix(models,ilist,type,states,streams,hset); else { ChkType('p',type); for (h=models; h!=NULL; h=h->next) { hmm = h->owner; for (j=2; j<hmm->numStates; j++) if (IsMember(states,j)) for (s=1; s<=hset->swidth[0];s++) if (IsMember(streams,s)) { /* tie -> spdf */ if (trace & T_ITM) printf(" %12s.state[%d].stream[%d]\n", HMMPhysName(hset,hmm),j,s); AddItem(hmm,hmm->svec[j].info->pdf+s,ilist); } } } FreeSet(streams); break; case DUR_KEY: ChkType('d',type); for (h=models; h!=NULL; h=h->next) { hmm = h->owner; for (j=2; j<hmm->numStates; j++) if (IsMember(states,j)) { /* tie ->dur */ if (trace & T_ITM) printf(" %12s.state[%d].dur\n", HMMPhysName(hset,hmm),j); AddItem(hmm,hmm->svec[j].info,ilist); } } break; case WEIGHTS_KEY: ChkType('w',type); for (h=models; h!=NULL; h=h->next) { hmm = h->owner; for (j=2; j<hmm->numStates; j++) if (IsMember(states,j)) { /* tie ->stream weights */ if (trace & T_ITM) printf(" %12s.state[%d].weights\n", HMMPhysName(hset,hmm),j); AddItem(hmm,hmm->svec[j].info,ilist); } } break; default: EdError("dur, weight, stream or mix expected"); } }
/* PMix: parse a mixture spec */ static void PMix(ILink models, ILink *ilist, char *type, IntSet states, IntSet streams,HMMSet *hset) { IntSet mixes; HMMDef *hmm; ILink h; int s,j,m; MixtureElem *me; StreamElem *ste; enum {TMIX, TMEAN, TCOV} what; mixes = CreateSet(maxMixes); PIndex(mixes); SkipSpaces(); what = TMIX; if (ch == '.') { ReadCh(); switch(GetKey()) { case MEAN_KEY: what = TMEAN; ChkType('u',type); break; case COV_KEY: what = TCOV; ChkType('a',type); break; default: EdError("Mean or Cov expected"); } } else ChkType('m',type); for (h=models; h!=NULL; h=h->next) { hmm = h->owner; for (j=2; j<hmm->numStates; j++) if (IsMember(states,j)) { ste = hmm->svec[j].info->pdf+1; for (s=1; s<=hset->swidth[0]; s++,ste++) if (IsMember(streams,s)) { me = ste->spdf.cpdf+1; for (m=1; m<=ste->nMix; m++,me++) if (me->weight>MINMIX && IsMember(mixes,m)) { switch (what) { case TMIX: /* tie ->mpdf */ if (trace & T_ITM) printf(" %12s.state[%d].stream[%d].mix[%d]\n", HMMPhysName(hset,hmm),j,s,m); AddItem(hmm,me,ilist); break; case TMEAN: /* tie ->mean */ ChkType('u',type); if (trace & T_ITM) printf(" %12s.state[%d].stream[%d].mix[%d].mean\n", HMMPhysName(hset,hmm),j,s,m); AddItem(hmm,me->mpdf,ilist); break; case TCOV: /* tie ->cov */ switch (me->mpdf->ckind) { case INVDIAGC: case DIAGC: ChkType('v',type); break; case FULLC: ChkType('i',type); break; case LLTC: ChkType('c',type); break; case XFORMC: ChkType('x',type); break; } if (trace & T_ITM) printf(" %12s.state[%d].stream[%d].mix[%d].%c\n", HMMPhysName(hset,hmm),j,s,m,*type); AddItem(hmm,me->mpdf,ilist); break; } } } } } FreeSet(mixes); }
/* * get_newsrcname() * get name of newsrc file with given name of nntp server * returns TRUE if name was found, FALSE if the search failed */ int get_newsrcname( char *newsrc_name, const char *nntpserver_name) /* return value is always ignored */ { FILE *fp; char *line_entry; char line[LEN]; char name_found[PATH_LEN]; int line_entry_counter; int found = 0; t_bool do_cpy = FALSE; if ((fp = fopen(local_newsrctable_file, "r")) != NULL) { while ((fgets(line, (int) sizeof(line), fp) != NULL) && (found != 1)) { line_entry_counter = 0; if (!strchr("# ;", line[0])) { while ((line_entry = strtok(line_entry_counter ? NULL : line, " \t\n")) != NULL) { line_entry_counter++; if ((line_entry_counter == 1) && (!strcasecmp(line_entry, nntpserver_name))) { found = 1; do_cpy = TRUE; } if ((line_entry_counter == 1) && ((!strcasecmp(line_entry, "default")) || (!strcmp(line_entry, "*")))) { found = 2; do_cpy = TRUE; } if (do_cpy && (line_entry_counter == 2)) { strcpy(name_found, line_entry); do_cpy = FALSE; } } } } fclose(fp); if (found) { char dir[PATH_LEN]; char tmp_newsrc[PATH_LEN]; int error = 0; if (!strfpath(name_found, tmp_newsrc, sizeof(tmp_newsrc), NULL)) { my_fprintf(stderr, _("couldn't expand %s\n"), name_found); error = 1; } else { if (tmp_newsrc[0] == '/') (void) strcpy(newsrc_name, tmp_newsrc); else joinpath(newsrc_name, homedir, tmp_newsrc); } (void) strcpy(dir, newsrc_name); if (strchr(dir, '/')) *strrchr(dir, '/') = (char) 0; if (!error) { /* FIXME - write a global permssion check routine */ if (access(dir, X_OK)) { my_fprintf(stderr, _(txt_error_no_enter_permission), dir); error = 1; } else if (access(newsrc_name, F_OK)) { my_fprintf(stderr, _(txt_error_no_such_file), newsrc_name); error = 2; } else if (access(dir, R_OK)) { my_fprintf(stderr, _(txt_error_no_read_permission), dir); error = 1; } else if (access(newsrc_name, R_OK)) { my_fprintf(stderr, _(txt_error_no_read_permission), newsrc_name); error = 1; } else if (access(dir, W_OK)) { my_fprintf(stderr, _(txt_error_no_write_permission), dir); error = 1; } else if (access(newsrc_name, W_OK)) { my_fprintf(stderr, _(txt_error_no_write_permission), newsrc_name); error = 1; } } if (error) { char ch; char default_ch = map_to_local(iKeyNrctblAlternative, &menukeymap.nrctbl_create); do { /* very ugly code, but curses is not initialized yet */ if (error >= 2) { default_ch = map_to_local(iKeyNrctblCreate, &menukeymap.nrctbl_create); printf("%s%c\b", _(txt_nrctbl_create), default_ch); } else printf("%s%c\b", _(txt_nrctbl_default), default_ch); if ((ch = (char) ReadCh()) == '\r' || ch == '\n') ch = default_ch; } while (!strchr(menukeymap.nrctbl_create.localkeys, ch)); printf("%c\n", ch); switch (map_to_default(ch, &menukeymap.nrctbl_create)) { case iKeyNrctblCreate: /* FIXME this doesn't check if we could create the file */ return TRUE; case iKeyNrctblDefault: joinpath(newsrc_name, homedir, ".newsrc"); return TRUE; case iKeyNrctblAlternative: sprintf(name_found, ".newsrc-%s", nntpserver_name); joinpath(newsrc_name, homedir, name_found); return TRUE; case iKeyNrctblQuit: exit(EXIT_SUCCESS); /* keep lint quiet: */ /* FALLTHROUGH */ case ESC: default: return TRUE; } } return TRUE; } } else write_newsrctable_file(); return FALSE; }
/* SkipSpaces: skip white space */ static void SkipSpaces(void) { while (isspace(ch)) ReadCh(); }
int InitScreen () { #ifndef INDEX_DAEMON char c,*ptr,buf[32]; /* * we're going to assume a terminal here... */ _clearscreen = "\033[1;1H\033[J"; _moveto = "\033[%d;%dH"; /* not a termcap string! */ _cleartoeoln = "\033[K"; _cleartoeos = "\033[J"; _setinverse = "\033[7m"; _clearinverse = "\033[0m"; _setunderline = "\033[4m"; _clearunderline = "\033[0m"; _terminalinit = "\033c"; _terminalend = "\033c"; _keypadlocal = ""; _keypadxmit = ""; InitWin (); _lines = _columns = -1; /* * Get lines and columns from environment settings - useful when * you're using something other than an Amiga window */ if (ptr = getenv("LINES")) { _lines = atol(ptr); } if (ptr = getenv("COLUMNS")) { _columns = atol(ptr); } /* * If that failed, try get a response from the console itself */ if (_lines == -1 || _columns == -1) { Raw (TRUE); tputs ("\2330 q",1,outchar); /* identify yourself */ fflush (stdout); getsize: while (ReadCh () != 0x9b) { ; /* Look for escape */ } /* get top */ ptr = buf; do { c = *ptr++ = ReadCh (); } while (isdigit(c)); if (c != ';') { goto getsize; } /* get right */ ptr = buf; do { c = *ptr++ = ReadCh (); } while (isdigit(c)); if (c != ';') { goto getsize; } /* get bottom */ ptr = buf; do { c = *ptr++ = ReadCh (); } while (isdigit(c)); if (c != ';') { goto getsize; } *ptr = 0; _lines = atol (buf); /* get right */ ptr = buf; do { c = *ptr++ = ReadCh (); } while (isdigit(c)); if (c != ' ') { goto getsize; } if (ReadCh () != 'r') { goto getsize; } *ptr = 0; _columns = atol (buf); } Raw (FALSE); return (TRUE); #else return (FALSE); #endif /* INDEX_DAEMON */ }
/* ** NextToken reads the next token from the input stream. It first ** skips all the blank characters and comments. */ static void NextToken(void) { SkipBlanks(); TChar = Char; TLine = Line; switch (Ch) { case '(': { Token = LPAREN; ReadCh(); break; } case ')': { Token = RPAREN; ReadCh(); break; } case '[': { Token = LBRACK; ReadCh(); break; } case ']': { Token = RBRACK; ReadCh(); break; } case '{': { Token = LBRACE; ReadCh(); break; } case '}': { Token = RBRACE; ReadCh(); break; } case '*': { Token = MULT; ReadCh(); break; } case '^': { Token = POWER; ReadCh(); break; } case ':': { ReadCh(); if (Ch != '=') SyntaxError("illegal character"); Token = DEQUALL; ReadCh(); break; } case '=': { ReadCh(); if (Ch != ':') Token = EQUAL; else { Token = DEQUALR; ReadCh(); } break; } case '+': { Token = PLUS; ReadCh(); break; } case '-': { Token = MINUS; ReadCh(); break; } case '<': { Token = LANGLE; ReadCh(); break; } case '>': { Token = RANGLE; ReadCh(); break; } case '|': { Token = PIPE; ReadCh(); break; } case ',': { Token = COMMA; ReadCh(); break; } case ';': { Token = SEMICOLON; ReadCh(); break; } case '0': case '1' : case '2' : case '3' : case '4' : case '5': case '6' : case '7' : case '8' : case '9' : { Token = NUMBER; Number(); break; } default : if (isalnum(Ch) || Ch == '_' || Ch == '.') { Token = GEN; Generator(); break; } else SyntaxError("illegal character"); } /* printf( "# NextToken(): %s\n", TokenName[Token] );*/ }
void alias(void) { /* * Work with alias commands... */ char name[NLEN], *address, buffer[SLEN]; char *commap; static int newaliases = 0; int ch, i; int nutitle = 0; int too_long; /* * We're going to try to match the way elm does it at * he main menu. I probably won't be able to use any * main menu routines, but I will "borrow" from them. RLH */ alias_main_state(); /* Save globals for return to main menu */ open_alias_files(FALSE); /* First, read the alias files. RLH */ alias_screen(newaliases); while (1) { redraw = 0; nucurr = 0; nufoot = 0; prompt(nls_Prompt); CleartoEOLN(); ch = GetKey(0); MoveCursor(LINES-3,strlen(nls_Prompt)); CleartoEOS(); dprint(3, (debugfile, "\n-- Alias command: %c\n\n", ch)); switch (ch) { case '?': redraw += alias_help(); break; #ifdef ALLOW_SUBSHELL case '!' : WriteChar('!'); alias_main_state(); /** reload index screen vars **/ redraw += subshell(); alias_main_state(); /** reload alias screen vars **/ break; #endif /* ALLOW_SUBSHELL */ case '$': PutLine(-1, -1, catgets(elm_msg_cat, AliasesSet, AliasesResync, "Resynchronize aliases...")); /* * Process deletions and then see if we need to * re-run the "newalias" routine. */ if (resync_aliases(newaliases)) { install_aliases(); newaliases = 0; redraw++; } break; case 'a': PutLine(-1, -1, catgets(elm_msg_cat, AliasesSet, AliasesAddCurrent, "Add address from current message...")); clear_error(); if (add_current_alias()) { newaliases++; nutitle++; } break; case 'c': if (curr_alias > 0) { PutLine(-1, -1, catgets(elm_msg_cat, AliasesSet, AliasesReplaceCurrent, "Replace current alias in database...")); clear_error(); if (add_alias(TRUE, curr_alias-1)) { newaliases++; nutitle++; } } else { show_error(catgets(elm_msg_cat, AliasesSet, AliasesNoneToReplace, "Warning: no aliases to replace!")); } break; case 'e': PutLine(LINES-3, strlen(nls_Prompt), catgets(elm_msg_cat, AliasesSet, AliasesEdit, "Edit %s..."), ALIAS_TEXT); /* * Process aliases.text for deletions, etc. You * have to do this *before* checking current because * all aliases could be marked for deletion. */ (void) resync_aliases(newaliases); if (edit_aliases_text()) { newaliases = 0; } redraw++; break; case 'm': if (curr_alias > 0) { PutLine(-1, -1, catgets(elm_msg_cat, AliasesSet, AliasesMail, "Mail...")); redraw += a_sendmsg(); } else { show_error(catgets(elm_msg_cat, AliasesSet, AliasesNoneToMail, "Warning: no aliases to send mail to!")); } break; case 'n': PutLine(-1, -1, catgets(elm_msg_cat, AliasesSet, AliasesAddNew, "Add a new alias to database...")); clear_error(); if (add_alias(FALSE, -1)) { newaliases++; nutitle++; } break; case 'q': case 'Q': case 'i': case 'I': case 'r': case 'R': PutLine(-1, -1, catgets(elm_msg_cat, AliasesSet, AliasesAddReturn, "Return to main menu...")); /* * leaving the alias system. Must check for * pending deletes, etc. prompt is set to FALSE * on uppercase letters so that deletions are * NOT queried. */ if (delete_aliases(newaliases, islower(ch))) { install_aliases(); newaliases = 0; } clear_error(); alias_main_state(); /* Done with aliases. */ return; case RETURN: case LINE_FEED: case ' ': case 'v': if (newaliases) { /* Need this ?? */ show_error(catgets(elm_msg_cat, AliasesSet, AliasesNotInstalled, "Warning: new aliases not installed yet!")); } if (curr_alias > 0) { if (aliases[curr_alias-1]->type & GROUP) { PutLine(LINES-1, 0, catgets(elm_msg_cat, AliasesSet, AliasesGroupAlias, "Group alias: %-60.60s"), aliases[curr_alias-1]->address); } else { PutLine(LINES-1, 0, catgets(elm_msg_cat, AliasesSet, AliasesAliasedAddress, "Aliased address: %-60.60s"), aliases[curr_alias-1]->address); } } else { show_error(catgets(elm_msg_cat, AliasesSet, AliasesNoneToView, "Warning: no aliases to view!")); } break; case 'x': case 'X': PutLine(-1, -1, catgets(elm_msg_cat, AliasesSet, AliasesAddReturn, "Return to main menu...")); exit_alias(); clear_error(); alias_main_state(); /* Done with aliases. */ return; case 'f': case 'F': if (curr_alias > 0) { clear_error(); strcpy(name, aliases[curr_alias-1]->alias); if (ch == 'F') { strcpy(buffer, catgets(elm_msg_cat, AliasesSet, AliasesFullyExpanded, "Fully expand alias: ")); PutLine(LINES-2, 0, buffer); if (enter_string(name, sizeof(name), -1, -1, ESTR_REPLACE) < 0 || name[0] == '\0') break; } too_long = FALSE; address = get_alias_address(name, TRUE, &too_long); if (address != NULL) { while (TRUE) { ClearScreen(); PutLine(2,0, catgets(elm_msg_cat, AliasesSet, AliasesAliasedFull, "Aliased address for:\t%s\n\r"), name); i = 4; while (i < LINES-2) { if ((commap = strchr(address, (int)',')) == NULL) { PutLine(i, 4, address); break; } *commap = '\0'; PutLine(i++, 4, address); address = commap+2; } PutLine(LINES-1, 0, catgets(elm_msg_cat, AliasesSet, AliasesPressReturn, "Press <return> to continue.")); (void) ReadCh(); if (commap == NULL) { redraw++; break; } } } else if (! too_long) { show_error(catgets(elm_msg_cat, AliasesSet, AliasesNotFound, "Not found.")); } } else { show_error(catgets(elm_msg_cat, AliasesSet, AliasesNoneToView, "Warning: no aliases to view!")); } break; case KEY_REDRAW: redraw = 1; break; /* * None of the menu specific commands were chosen, therefore * it must be a "motion" command (or an error). */ default : motion(ch); } if (redraw) { /* Redraw screen if necessary */ alias_screen(newaliases); nutitle = 0; } if (nutitle) { /* Redraw title if necessary */ alias_title(newaliases); nutitle = 0; } check_range(); if (nucurr == NEW_PAGE) show_headers(); else if (nucurr == SAME_PAGE) show_current(); else if (nufoot) { if (mini_menu) { MoveCursor(LINES-7, 0); CleartoEOS(); show_alias_menu(); } else { MoveCursor(LINES-4, 0); CleartoEOS(); } show_last_error(); /* for those operations that have to * clear the footer except for a message. */ } } /* BIG while loop... */ }
static int alias_help(void) { /* * Help section for the alias menu... * * Return non-0 if main part of screen overwritten, else 0 */ int ch; int redraw=0; char *alias_prompt; if (mini_menu) alias_prompt = catgets(elm_msg_cat, AliasesSet, AliasesShortKey, "Key: "); else alias_prompt = catgets(elm_msg_cat, AliasesSet, AliasesLongKey, "Key you want help for: "); MoveCursor(LINES-3, 0); CleartoEOS(); if (mini_menu) { CenterLine(LINES-3, catgets(elm_msg_cat, AliasesSet, AliasesKeyMenu, "Press the key you want help for, '?' for a key list, or '.' to exit help")); } lower_prompt(alias_prompt); while ((ch = ReadCh()) != '.') { switch(ch) { case '?' : display_helpfile("alias"); redraw++; return(redraw); case '$': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpDollar, "$ = Force resynchronization of aliases, processing additions and deletions.")); break; case '/': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpSlash, "/ = Search for specified name or alias in list.")); break; case RETURN: case LINE_FEED: case ' ': case 'v': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpv, "v = View the address for the currently selected alias.")); break; case 'a': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpa, "a = Add (return) address of current message to alias database.")); break; case 'c': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpc, "c = Change current user alias, modifying alias database at next resync.")); break; case 'd': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpd, "d = Mark the current alias for deletion from alias database.")); break; case ctrl('D'): show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlD, "^D = Mark for deletion user aliases matching specified pattern.")); break; case 'e': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpe, "e = Edit the alias text file directly (will run newalias).")); break; case 'f': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpf, "f = Display fully expanded address of current alias.")); break; case 'l': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpl, "l = Limit displayed aliases on the specified criteria.")); break; case ctrl('L'): show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlL, "^L = Rewrite the screen.")); break; case 'm': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpm, "m = Send mail to the current or tagged aliases.")); break; case 'n': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpn, "n = Add a new user alias, adding to alias database at next resync.")); break; case 'r': case 'q': case 'i': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpi, "r,q,i = Return from alias menu (with prompting).")); break; case 'R': case 'Q': case 'I': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpQ, "R,Q,I = Return from alias menu (no prompting).")); break; case 't': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpt, "t = Tag current alias for further operations.")); break; case 'T': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpT, "T = Tag current alias and go to next alias.")); break; case ctrl('T'): show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlT, "^T = Tag aliases matching specified pattern.")); break; case 'u': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpu, "u = Unmark the current alias for deletion from alias database.")); break; case ctrl('U'): show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpCtrlU, "^U = Mark for undeletion user aliases matching specified pattern.")); break; case 'x': case 'X': show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpX, "x = Exit from alias menu, abandoning any pending deletions.")); break; default : show_error(catgets(elm_msg_cat, AliasesSet, AliasesHelpNoHelp, "That key isn't used in this section.")); break; } lower_prompt(alias_prompt); } /* Remove help lines */ MoveCursor(LINES-3, 0); CleartoEOS(); return(redraw); }
options() { /** change options... **/ /* return: * > 0 if restort was done - to indicate we might need to * change the page of our headers as a consequence * of the new sort order * < 0 if user entered 'x' to quit elm immediately * 0 otherwise */ int ch, resort = 0; char *strcpy(), temp[SLEN]; /* needed when an option is run through * expand_env(), because that function * is destructive of the original */ display_options(); clearerr(stdin); while(1) { ClearLine(LINES-4); Centerline(LINES-4, "Select first letter of option line, '>' to save, or 'i' to return to index."); PutLine0(LINES-2, 0, "Command: "); ch = ReadCh(); ch = tolower(ch); clear_error(); /* remove possible "sorting" message etc... */ one_liner(one_liner_for(ch)); switch (ch) { case 'c' : optionally_enter(raw_calendar_file, 2, 23, FALSE, FALSE); strcpy(temp, raw_calendar_file); expand_env(calendar_file, temp); break; case 'd' : optionally_enter(raw_pager, 3, 23, FALSE, FALSE); strcpy(temp, raw_pager); expand_env(pager, temp); clear_pages = (equal(pager, "builtin+") || equal(pager, "internal+")); break; case 'e' : optionally_enter(raw_editor, 4, 23, FALSE, FALSE); strcpy(temp, raw_editor); expand_env(editor, temp); break; case 'f' : optionally_enter(raw_folders, 5, 23, FALSE, FALSE); strcpy(temp, raw_folders); expand_env(folders, temp); break; case 's' : if(change_sort(6,23)) resort++; break; case 'o' : optionally_enter(raw_sentmail, 7, 23, FALSE, FALSE); strcpy(temp, raw_sentmail); expand_env(sent_mail, temp); break; case 'p' : optionally_enter(raw_printout, 8, 23, FALSE, FALSE); strcpy(temp, raw_printout); expand_env(printout, temp); break; case 'y' : optionally_enter(full_username, 9, 23, FALSE, FALSE); break; case 'a' : on_or_off(&arrow_cursor, 12, 23); break; case 'm' : on_or_off(&mini_menu, 13, 23); headers_per_page = LINES - (mini_menu ? 13 : 8); break; case 'u' : switch_user_level(&user_level,15, 23); break; case 'n' : on_or_off(&names_only, 16, 23); break; case '?' : options_help(); PutLine0(LINES-2,0,"Command: "); break; case '>' : printf("Save options in .elm/elmrc..."); fflush(stdout); save_options(); break; case 'x' : return(-1); /* exit elm */ case 'q' : /* pop back up to previous level, in this case == 'i' */ case 'i' : /* return to index screen */ return(resort ? 1 : 0); case ctrl('L'): display_options(); break; default: error("Command unknown!"); } } }
char * tin_getline( const char *prompt, int number_only, /* 1=positive numbers only, 2=negative too */ const char *str, int max_chars, t_bool passwd, int which_hist) { int c, i, loc, tmp, gl_max; #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE) wint_t wc; #else char *buf = gl_buf; #endif /* MULTIBYTE_ABLE && !NO_LOCALE */ is_passwd = passwd; set_xclick_off(); if (prompt == NULL) prompt = ""; gl_buf[0] = 0; /* used as end of input indicator */ gl_fixup(-1, 0); /* this resets gl_fixup */ gl_width = cCOLS - strlen(prompt); gl_prompt = prompt; gl_pos = gl_cnt = 0; if (max_chars == 0) { if (number_only) gl_max = 6; else gl_max = BUF_SIZE; } else gl_max = max_chars; my_fputs(prompt, stdout); cursoron(); my_flush(); if (gl_in_hook) { loc = gl_in_hook(gl_buf); if (loc >= 0) gl_fixup(0, BUF_SIZE); } if (!cmd_line && gl_max == BUF_SIZE) CleartoEOLN(); #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE) if (str != NULL) { wchar_t wbuf[LEN]; if (mbstowcs(wbuf, str, ARRAY_SIZE(wbuf) - 1) != (size_t) -1) { wbuf[ARRAY_SIZE(wbuf) - 1] = (wchar_t) '\0'; for (i = 0; wbuf[i]; i++) gl_addwchar(wbuf[i]); } } while ((wc = ReadWch()) != WEOF) { if ((gl_cnt < gl_max) && iswprint(wc)) { if (number_only) { if (iswdigit(wc)) { gl_addwchar(wc); /* Minus */ } else if (number_only == 2 && gl_pos == 0 && wc == (wint_t) '-') { gl_addwchar(wc); } else { ring_bell(); } } else gl_addwchar(wc); } else { c = (int) wc; switch (wc) { #else if (str != NULL) { for (i = 0; str[i]; i++) gl_addchar(str[i]); } while ((c = ReadCh()) != EOF) { c &= 0xff; if ((gl_cnt < gl_max) && my_isprint(c)) { if (number_only) { if (isdigit(c)) { gl_addchar(c); /* Minus */ } else if (number_only == 2 && gl_pos == 0 && c == '-') { gl_addchar(c); } else { ring_bell(); } } else gl_addchar(c); } else { switch (c) { #endif /* MULTIBYTE_ABLE && !NO_LOCALE */ case ESC: /* abort */ #ifdef HAVE_KEY_PREFIX case KEY_PREFIX: #endif /* HAVE_KEY_PREFIX */ switch (get_arrow_key(c)) { case KEYMAP_UP: case KEYMAP_PAGE_UP: hist_prev(which_hist); break; case KEYMAP_PAGE_DOWN: case KEYMAP_DOWN: hist_next(which_hist); break; case KEYMAP_RIGHT: gl_fixup(-1, gl_pos + 1); break; case KEYMAP_LEFT: gl_fixup(-1, gl_pos - 1); break; case KEYMAP_HOME: gl_fixup(-1, 0); break; case KEYMAP_END: gl_fixup(-1, gl_cnt); break; case KEYMAP_DEL: gl_del(0); break; case KEYMAP_INS: #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE) gl_addwchar((wint_t) ' '); #else gl_addchar(' '); #endif /* MULTIBYTE_ABLE && !NO_LOCALE */ break; default: return (char *) 0; } break; case '\n': /* newline */ case '\r': gl_newline(which_hist); #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE) wcstombs(buf, gl_buf, BUF_SIZE - 1); #endif /* MULTIBYTE_ABLE && !NO_LOCALE */ return buf; case CTRL_A: gl_fixup(-1, 0); break; case CTRL_B: gl_fixup(-1, gl_pos - 1); break; case CTRL_D: if (gl_cnt == 0) { gl_buf[0] = 0; my_fputc('\n', stdout); #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE) wcstombs(buf, gl_buf, BUF_SIZE - 1); #endif /* MULTIBYTE_ABLE && !NO_LOCALE */ return buf; } else gl_del(0); break; case CTRL_E: gl_fixup(-1, gl_cnt); break; case CTRL_F: gl_fixup(-1, gl_pos + 1); break; case CTRL_H: case DEL: gl_del(-1); break; case TAB: if (gl_tab_hook) { tmp = gl_pos; loc = gl_tab_hook(gl_buf, strlen(gl_prompt), &tmp); if (loc >= 0 || tmp != gl_pos) gl_fixup(loc, tmp); } break; case CTRL_W: gl_kill_back_word(); break; case CTRL_U: gl_fixup(-1, 0); /* FALLTHROUGH */ case CTRL_K: gl_kill(); break; case CTRL_L: case CTRL_R: gl_redraw(); break; case CTRL_N: hist_next(which_hist); break; case CTRL_P: hist_prev(which_hist); break; default: ring_bell(); break; } } } #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE) wcstombs(buf, gl_buf, BUF_SIZE - 1); #endif /* MULTIBYTE_ABLE && !NO_LOCALE */ return buf; } /* * adds the character c to the input buffer at current location if * the character is in the allowed template of characters */ static void #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE) gl_addwchar( wint_t wc) #else gl_addchar( int c) #endif /* MULTIBYTE_ABLE && !NO_LOCALE */ { int i; /* * Crashing is always the worst solution IMHO. So as a quick hack, * ignore characters silently, if buffer is full. To allow a final * newline, leave space for one more character. Just a hack too. * This was the original code: * if (gl_cnt >= BUF_SIZE - 1) { error_message("tin_getline: input buffer overflow"); giveup(); } */ if (gl_cnt >= BUF_SIZE - 2) return; for (i = gl_cnt; i >= gl_pos; i--) gl_buf[i + 1] = gl_buf[i]; #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE) gl_buf[gl_pos] = (wchar_t) wc; #else gl_buf[gl_pos] = c; #endif /* MULTIBYTE_ABLE && !NO_LOCALE */ gl_fixup(gl_pos, gl_pos + 1); } /* * Cleans up entire line before returning to caller. A \n is appended. * If line longer than screen, we redraw starting at beginning */ static void gl_newline( int w) { int change = gl_cnt; int len = gl_cnt; int loc = gl_width - 5; /* shifts line back to start position */ if (gl_cnt >= BUF_SIZE - 1) { /* * Like above: avoid crashing if possible. gl_addchar() now * leaves one space left for the newline, so this part of the * code should never be reached. A proper implementation is * desirable though. */ error_message("tin_getline: input buffer overflow"); giveup(); } hist_add(w); /* only adds if nonblank */ if (gl_out_hook) { change = gl_out_hook(gl_buf); #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE) len = wcslen(gl_buf); #else len = strlen(gl_buf); #endif /* MULTIBYTE_ABLE && !NO_LOCALE */ } if (loc > len) loc = len; gl_fixup(change, loc); /* must do this before appending \n */ #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE) gl_buf[len] = (wchar_t) '\0'; #else gl_buf[len] = '\0'; #endif /* MULTIBYTE_ABLE && !NO_LOCALE */ } /* * Delete a character. The loc variable can be: * -1 : delete character to left of cursor * 0 : delete character under cursor */ static void gl_del( int loc) { int i; if ((loc == -1 && gl_pos > 0) || (loc == 0 && gl_pos < gl_cnt)) { for (i = gl_pos + loc; i < gl_cnt; i++) gl_buf[i] = gl_buf[i + 1]; gl_fixup(gl_pos + loc, gl_pos + loc); } else ring_bell(); }