#define TELLME(x) fprintf(stderr,"V_call %d\n",x) ; # /*********************************************************************** $Id: V_call.c,v 2.1 2006/02/09 03:08:58 glynn Exp $ Modified by Jacques Bouchard and Markus Neteler 6/99 to make cursor keys working. Exit now with ESC-CR. NAME: V_call() FUNCTION: Interactively allow the user to enter answers into all available fields (as previously defined). Answer fields have been created with calls to V_ques() Information fields have been created using V_const() General text has been created with calls to V_line() USAGE: V_call() PARAMETERS: RETURNS: 1 user entered ESC to continue 0 user entered ctrl-C to cancel ALGORITHM: | Zero out screen answer locations | Initial curses screens | Display text, constants, and answer fields | Write text (results from V_line() calls) to curses window | Write constants (results from V_const() calls) to curses window | Write answers (results from V_ques() calls) to curses window | Take commands from the keyboard | switch on commands: | case CR: case NL: case UP: case ESC: | switch on answer type | case string | remove trailing non-alphanumeric characters | copy answer to target denoted in V_ques() call | blank out screen line | copy target to curses window | case integer | run atoi on answer, putting results in target | denoted in V_ques() call | blank out screen line | printf target to curses window | case long | run atol on answer, putting results in target | denoted in V_ques() call | blank out screen line | printf target to curses window | case float, double | run sscanf on answer, putting results in target | denoted in V_ques() call | blank out screen line | printf target to curses window | default: | do nothing | if ESC+CR return from V_call() | if UP shift to previous question | if CR or NL shift to next question | case BS: Move cursor back one column in current question | case FS: Move cursor forward one column in current | question | case RPLT: Replot the current screen image | case DUMP: Dump (append) the current window to the user's | home dir. | default: If an alphanumeric, put that char on the screen | and in the current answer field | call V_exit (erase screen and exit curses) CALLS: V_init() Vask routine to initialize curses V_exit() Vask routine to exit curses V__dump_window() V_ask V__remove_trail() V_ask addch() curses routine addstr() curses routine move() curses routine putc() curses routine refresh() curses routine getch() curses routine wrefresh() curses routine sprintf() UNIX strcpy() UNIX ***********************************************************************/ #include #include #include #include static int centered(const char *); static int fmt(char *,int,double); /* define the V__ struct defined in vask.h */ struct V__ V__ ; #define DUMP 001 #define BS 010 #define FS 014 #define NL 012 #define UP 013 #define CR 015 #define RPLT 022 #define ESC 033 #define CTRLC 003 #define TARGET V__.usr_answ[at_answer].targetptr #define ROW V__.usr_answ[at_answer].row #define COL V__.usr_answ[at_answer].col #define LENGTH V__.usr_answ[at_answer].length #define TYPE V__.usr_answ[at_answer].var_type #define ANSWER scr_answ[at_answer].position #define RELINE do { \ move(ROW, COL) ; \ for (incr2=0;incr2 TO CONTINUE") ; if (interrupts_ok) { sprintf(temp,"(OR TO %s)", V__.interrupt_msg); centered(temp); } /* Begin taking commands/answers from terminal */ at_answer = 0 ; new_answer = 0 ; ans_col = 0 ; move(ROW, COL) ; refresh() ; for (done = 0; !done; ) { getyx (stdscr, y, x); newchar = getch(); switch (newchar) { case ERR: break; case ESC: if (V__.NUM_ANSW <= 0) done = 1; break; case CTRLC: if (interrupts_ok || V__.NUM_ANSW <= 0) done = 1; break; #ifdef KEY_UP case KEY_UP: #endif case UP: new_answer = (at_answer+num_answers-1) % num_answers ; ans_col = 0 ; break ; #ifdef KEY_DOWN case KEY_DOWN: #endif case CR: case NL: new_answer = (at_answer+1) % num_answers ; ans_col = 0 ; if (lastchar == ESC && newchar == CR) done = 1; break ; #ifdef KEY_LEFT case KEY_LEFT: ans_col = (ans_col-1 >= 0) ? ans_col-1 : 0 ; break ; #endif #ifdef KEY_BACKSPACE case KEY_BACKSPACE: #endif case BS: ans_col = (ans_col-1 >= 0) ? ans_col-1 : 0 ; ANSWER[ans_col] = ' ' ; move(ROW, COL + ans_col) ; addch(' ') ; break ; #ifdef KEY_RIGHT case KEY_RIGHT: #endif case FS: ans_col = (ans_col+1 < LENGTH && ANSWER[ans_col]) ? ans_col+1 : ans_col ; break ; #ifdef KEY_HOME case KEY_HOME: ans_col = 0 ; break ; #endif #ifdef KEY_END case KEY_END: for (ans_col = 0; ans_col < LENGTH && ANSWER[ans_col]; ans_col++) ; break ; #endif #ifdef KEY_REFRESH case KEY_REFRESH: #endif case RPLT: wrefresh(curscr) ; break ; #ifdef KEY_PRINT case KEY_PRINT: #endif case DUMP: V__dump_window() ; break ; case '\177': break; default: if (ans_col < LENGTH && newchar >= 040 && newchar <= 0377) { addch(newchar) ; ANSWER[ans_col] = newchar ; ans_col++ ; } break ; } if (new_answer != at_answer || done) { V__remove_trail(LENGTH, ANSWER) ; switch (TYPE) { case 's': strcpy(TARGET.c, ANSWER) ; RELINE ; addstr(TARGET.c) ; break ; case 'i': *TARGET.i = atoi(ANSWER) ; RELINE ; sprintf(temp,"%d", *TARGET.i) ; addstr (temp) ; break ; case 'l': *TARGET.l = atol(ANSWER) ; RELINE ; sprintf(temp,"%ld", *TARGET.l) ; addstr (temp) ; break ; case 'f': sscanf (ANSWER,"%f",TARGET.f); RELINE ; fmt (ANSWER, V__.usr_answ[at_answer].decimal_places, (double)*TARGET.f); sscanf (ANSWER,"%f",TARGET.f); addstr (ANSWER) ; break ; case 'd': sscanf (ANSWER,"%lf",TARGET.d); RELINE ; fmt (ANSWER, V__.usr_answ[at_answer].decimal_places, (double)*TARGET.d); sscanf (ANSWER,"%lf",TARGET.d); addstr (ANSWER) ; break ; default: break ; } at_answer = new_answer; } lastchar = newchar; move(ROW, COL + ans_col) ; refresh(); if (done) { interrupts_ok = 0; V_exit() ; return (newchar != CTRLC); } } } /*! * \brief allow ctrl-c * * V_call() normally only allows the * ESC character to end the interactive input session. Sometimes it is desirable * to allow the user to cancel the session. To provide this alternate means of * exit, the programmer can call V_intrpt_ok() before V_call(). This allows * the user to enter Ctrl-C, which causes V_call() to return a value of 0 * instead of 1. * A message is automatically supplied to the user on line 23 saying to use * Ctrl-C to cancel the input session. The normal message accompanying V_call() * is moved up to line 22. * Note. When V_intrpt_ok() is called, the programmer must limit the * use of V_line(), V_ques(), and V_const() to lines 0-21. * * \return int */ int V_intrpt_ok(void) { interrupts_ok = 1; /* will be set false when V_call() exists */ return 0; } /*! * \brief change ctrl-c message * * A call to * V_intrpt_msg() changes the default V_intrpt_ok() message from (OR * TO CANCEL) to (OR TO msg). The message is (re)set * to the default by V_clear(). * * \param text * \return int */ int V_intrpt_msg (const char *msg) { strcpy (V__.interrupt_msg, msg); return 0; } static int fmt(char *s,int n, double x) { char buf[20]; if (n >= 0) sprintf (buf, "%%.%dlf", n); else strcpy (buf, "%.5lf"); /* I had to use .5lf instead of just lf since a number like 65.8 got sprintf'ed as 65.800003 * this is a hack - I admit it. */ sprintf (s, buf, x); if (n < 0) V__trim_decimal(s); return 0; } static int centered(const char *msg) { int indent; indent = (80 - strlen(msg))/2; while (indent-- > 0) addstr(" "); addstr(msg); addstr("\n"); return 0; }