V_call.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. /**
  2. * \file V_call.c
  3. *
  4. * \brief Interactive call functions.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or (at
  9. * your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. *
  20. * \note Modified by Jacques Bouchard and Markus Neteler 6/99 to make
  21. * cursor keys working. Exit now with ESC-CR.
  22. *
  23. * \author GRASS GIS Development Team
  24. *
  25. * \date 1999
  26. * \date $Id$
  27. */
  28. /*
  29. ALGORITHM:
  30. | Zero out screen answer locations
  31. | Initial curses screens
  32. | Display text, constants, and answer fields
  33. | Write text (results from V_line() calls) to curses window
  34. | Write constants (results from V_const() calls) to curses window
  35. | Write answers (results from V_ques() calls) to curses window
  36. | Take commands from the keyboard
  37. | switch on commands:
  38. | case CR: case NL: case UP: case ESC:
  39. | switch on answer type
  40. | case string
  41. | remove trailing non-alphanumeric characters
  42. | copy answer to target denoted in V_ques() call
  43. | blank out screen line
  44. | copy target to curses window
  45. | case integer
  46. | run atoi on answer, putting results in target
  47. | denoted in V_ques() call
  48. | blank out screen line
  49. | printf target to curses window
  50. | case long
  51. | run atol on answer, putting results in target
  52. | denoted in V_ques() call
  53. | blank out screen line
  54. | printf target to curses window
  55. | case float, double
  56. | run sscanf on answer, putting results in target
  57. | denoted in V_ques() call
  58. | blank out screen line
  59. | printf target to curses window
  60. | default:
  61. | do nothing
  62. | if ESC+CR return from V_call()
  63. | if UP shift to previous question
  64. | if CR or NL shift to next question
  65. | case BS: Move cursor back one column in current question
  66. | case FS: Move cursor forward one column in current
  67. | question
  68. | case RPLT: Replot the current screen image
  69. | case DUMP: Dump (append) the current window to the user's
  70. | home dir.
  71. | default: If an alphanumeric, put that char on the screen
  72. | and in the current answer field
  73. | call V_exit (erase screen and exit curses)
  74. ***********************************************************************/
  75. #include <grass/config.h>
  76. #include <stdio.h>
  77. #include <stdlib.h>
  78. #include <string.h>
  79. #include <grass/vask.h>
  80. static void centered(const char *);
  81. static void fmt(char *,int,double);
  82. /* define the V__ struct defined in vask.h */
  83. struct V__ V__ ;
  84. #define DUMP 001
  85. #define BS 010
  86. #define FS 014
  87. #define NL 012
  88. #define UP 013
  89. #define CR 015
  90. #define RPLT 022
  91. #define ESC 033
  92. #define CTRLC 003
  93. #define TARGET V__.usr_answ[at_answer].targetptr
  94. #define ROW V__.usr_answ[at_answer].row
  95. #define COL V__.usr_answ[at_answer].col
  96. #define LENGTH V__.usr_answ[at_answer].length
  97. #define TYPE V__.usr_answ[at_answer].var_type
  98. #define ANSWER scr_answ[at_answer].position
  99. #define RELINE do { \
  100. move(ROW, COL) ; \
  101. for (incr2=0;incr2<LENGTH; incr2++) \
  102. addch('_') ; \
  103. move(ROW, COL) ; \
  104. } while (0)
  105. /* flag ctrl-c is to be allowed */
  106. static int interrupts_ok = 0; /* mod shapiro */
  107. /**
  108. * \fn int V_call (void)
  109. *
  110. * \brief Interact with the user.
  111. *
  112. * Interactively allow the user to enter answers into all available
  113. * fields (as previously defined). Answer fields have been created with
  114. * calls to <i>V_ques()</i>. Information fields have been created using
  115. * <i>V_const()</i>. General text has been created with calls to
  116. * <i>V_line()</i>.
  117. *
  118. * <i>V_call()</i> clears the screen and writes the text and data values
  119. * specified by <i>V_line()</i>, <i>V_ques()</i> and <i>V_const()</i> to
  120. * the screen. It interfaces with the user, collecting user responses in
  121. * the <i>V_ques()</i> fields until the user is satisfied. A message is
  122. * automatically supplied on line number 23, explaining to the user to
  123. * enter an ESC when all inputs have been supplied as desired.
  124. * <i>V_call()</i> ends when the user hits ESC and returns a value of 1
  125. * (but see <i>V_intrpt_ok()</i> below). No error checking is done by
  126. * <i>V_call()</i>. Instead, all variables used in <i>V_ques()</i>
  127. * calls must be checked upon return from <i>V_call()</i>. If the user
  128. * has supplied inappropriate information, the user can be informed, and
  129. * the input prompted for again by further calls to <i>V_call()</i>.
  130. *
  131. * \return 1 user entered ESC to continue
  132. * \return 0 user entered CTRL-C to cancel
  133. * \return -1 no match
  134. */
  135. int V_call(void)
  136. {
  137. int incr ;
  138. int incr2 ;
  139. int num_answers ;
  140. int at_answer ;
  141. int at_constant ;
  142. int ans_col = 0;
  143. int newchar ;
  144. int lastchar = 0;
  145. int new_answer = 0;
  146. struct { char position[80]; } scr_answ[MAX_ANSW] ;
  147. int y,x; /* shapiro */
  148. char temp[100];
  149. int done;
  150. /* Zero out screen answer locations */
  151. for(incr=0; incr<MAX_ANSW; incr++)
  152. for(incr2=0; incr2<80; incr2++)
  153. scr_answ[incr].position[incr2] = 000 ;
  154. /* Initialize the curses windows */
  155. V_init() ;
  156. /* Display text */
  157. for (incr=0; incr<MAX_LINE; incr++)
  158. {
  159. move (incr, 0) ;
  160. addstr(V__.page.line[incr]) ;
  161. }
  162. /* Display constants */
  163. for (at_constant=0; at_constant < V__.NUM_CONST; at_constant++)
  164. {
  165. move(V__.constant[at_constant].row, V__.constant[at_constant].col) ;
  166. switch (V__.constant[at_constant].var_type)
  167. {
  168. case 's':
  169. addstr(V__.constant[at_constant].targetptr.c) ;
  170. break ;
  171. case 'i':
  172. sprintf(temp,"%d", *V__.constant[at_constant].targetptr.i) ;
  173. addstr (temp) ;
  174. break ;
  175. case 'l':
  176. sprintf(temp,"%ld", *V__.constant[at_constant].targetptr.l) ;
  177. addstr (temp) ;
  178. break ;
  179. case 'f':
  180. fmt (temp, V__.constant[at_constant].decimal_places,
  181. (double)*V__.constant[at_constant].targetptr.f) ;
  182. addstr (temp) ;
  183. break ;
  184. case 'd':
  185. fmt (temp, V__.constant[at_constant].decimal_places,
  186. (double)*V__.constant[at_constant].targetptr.d) ;
  187. addstr (temp) ;
  188. break ;
  189. default:
  190. break ;
  191. }
  192. }
  193. /* Display answer locations */
  194. for (at_answer=0; at_answer < V__.NUM_ANSW; at_answer++)
  195. {
  196. /* clear ANSWER */
  197. for (incr=0; incr<80; incr++)
  198. scr_answ[at_answer].position[incr] = 000 ;
  199. switch (TYPE)
  200. {
  201. case 's':
  202. strcpy(ANSWER, TARGET.c) ;
  203. RELINE ;
  204. for (incr=0; incr<LENGTH; incr++)
  205. {
  206. if ( *(TARGET.c + incr) == '\000')
  207. while (incr++ < LENGTH)
  208. addch('_') ;
  209. else addch( *(TARGET.c + incr) ) ;
  210. }
  211. break ;
  212. case 'i':
  213. sprintf(ANSWER,"%d",*TARGET.i) ;
  214. RELINE ;
  215. addstr (ANSWER);
  216. break ;
  217. case 'l':
  218. sprintf(ANSWER,"%ld",*TARGET.l) ;
  219. RELINE ;
  220. addstr (ANSWER);
  221. break ;
  222. case 'f':
  223. fmt (ANSWER, V__.usr_answ[at_answer].decimal_places, (double)*TARGET.f);
  224. RELINE ;
  225. addstr (ANSWER);
  226. break ;
  227. case 'd':
  228. fmt (ANSWER, V__.usr_answ[at_answer].decimal_places, (double)*TARGET.d);
  229. RELINE ;
  230. addstr (ANSWER);
  231. break ;
  232. default:
  233. break ;
  234. }
  235. }
  236. num_answers = at_answer ;
  237. if (interrupts_ok)
  238. move(22,0) ;
  239. else
  240. move(23,0) ;
  241. centered("AFTER COMPLETING ALL ANSWERS, HIT <ESC><ENTER> TO CONTINUE") ;
  242. if (interrupts_ok)
  243. {
  244. sprintf(temp,"(OR <Ctrl-C> TO %s)", V__.interrupt_msg);
  245. centered(temp);
  246. }
  247. /* Begin taking commands/answers from terminal */
  248. at_answer = 0 ;
  249. move(ROW, COL) ;
  250. refresh() ;
  251. for (done = 0; !done; )
  252. {
  253. getyx (stdscr, y, x);
  254. newchar = getch();
  255. switch (newchar)
  256. {
  257. case ERR:
  258. break;
  259. case ESC:
  260. if (V__.NUM_ANSW <= 0)
  261. done = 1;
  262. break;
  263. case CTRLC:
  264. if (interrupts_ok || V__.NUM_ANSW <= 0)
  265. done = 1;
  266. break;
  267. #ifdef KEY_UP
  268. case KEY_UP:
  269. #endif
  270. case UP:
  271. new_answer = (at_answer+num_answers-1) % num_answers ;
  272. ans_col = 0 ;
  273. break ;
  274. #ifdef KEY_DOWN
  275. case KEY_DOWN:
  276. #endif
  277. case CR:
  278. case NL:
  279. new_answer = (at_answer+1) % num_answers ;
  280. ans_col = 0 ;
  281. if (lastchar == ESC && (newchar == CR || newchar == NL))
  282. done = 1;
  283. break ;
  284. #ifdef KEY_LEFT
  285. case KEY_LEFT:
  286. ans_col = (ans_col-1 >= 0) ? ans_col-1 : 0 ;
  287. break ;
  288. #endif
  289. #ifdef KEY_BACKSPACE
  290. case KEY_BACKSPACE:
  291. #endif
  292. case BS:
  293. ans_col = (ans_col-1 >= 0) ? ans_col-1 : 0 ;
  294. ANSWER[ans_col] = ' ' ;
  295. move(ROW, COL + ans_col) ;
  296. addch(' ') ;
  297. break ;
  298. #ifdef KEY_RIGHT
  299. case KEY_RIGHT:
  300. #endif
  301. case FS:
  302. ans_col = (ans_col+1 < LENGTH && ANSWER[ans_col]) ? ans_col+1 : ans_col ;
  303. break ;
  304. #ifdef KEY_HOME
  305. case KEY_HOME:
  306. ans_col = 0 ;
  307. break ;
  308. #endif
  309. #ifdef KEY_END
  310. case KEY_END:
  311. for (ans_col = 0; ans_col < LENGTH && ANSWER[ans_col]; ans_col++)
  312. ;
  313. break ;
  314. #endif
  315. #ifdef KEY_REFRESH
  316. case KEY_REFRESH:
  317. #endif
  318. case RPLT:
  319. wrefresh(curscr) ;
  320. break ;
  321. #ifdef KEY_PRINT
  322. case KEY_PRINT:
  323. #endif
  324. case DUMP:
  325. V__dump_window() ;
  326. break ;
  327. case '\177':
  328. break;
  329. default:
  330. if (ans_col < LENGTH && newchar >= 040 && newchar <= 0377)
  331. {
  332. addch(newchar) ;
  333. ANSWER[ans_col] = newchar ;
  334. ans_col++ ;
  335. }
  336. break ;
  337. }
  338. if (new_answer != at_answer || done)
  339. {
  340. V__remove_trail(LENGTH, ANSWER) ;
  341. switch (TYPE)
  342. {
  343. case 's':
  344. strcpy(TARGET.c, ANSWER) ;
  345. RELINE ;
  346. addstr(TARGET.c) ;
  347. break ;
  348. case 'i':
  349. *TARGET.i = atoi(ANSWER) ;
  350. RELINE ;
  351. sprintf(temp,"%d", *TARGET.i) ;
  352. addstr (temp) ;
  353. break ;
  354. case 'l':
  355. *TARGET.l = atol(ANSWER) ;
  356. RELINE ;
  357. sprintf(temp,"%ld", *TARGET.l) ;
  358. addstr (temp) ;
  359. break ;
  360. case 'f':
  361. sscanf (ANSWER,"%f",TARGET.f);
  362. RELINE ;
  363. fmt (ANSWER, V__.usr_answ[at_answer].decimal_places,
  364. (double)*TARGET.f);
  365. sscanf (ANSWER,"%f",TARGET.f);
  366. addstr (ANSWER) ;
  367. break ;
  368. case 'd':
  369. sscanf (ANSWER,"%lf",TARGET.d);
  370. RELINE ;
  371. fmt (ANSWER, V__.usr_answ[at_answer].decimal_places,
  372. (double)*TARGET.d);
  373. sscanf (ANSWER,"%lf",TARGET.d);
  374. addstr (ANSWER) ;
  375. break ;
  376. default:
  377. break ;
  378. }
  379. at_answer = new_answer;
  380. }
  381. lastchar = newchar;
  382. move(ROW, COL + ans_col) ;
  383. refresh();
  384. if (done)
  385. {
  386. interrupts_ok = 0;
  387. V_exit() ;
  388. return (newchar != CTRLC);
  389. }
  390. }
  391. return -1;
  392. }
  393. /**
  394. * \fn int V_intrpt_ok (void)
  395. *
  396. * \brief Allow CTRL-C.
  397. *
  398. * <i>V_call()</i> normally only allows the ESC character to end the
  399. * interactive input session. Sometimes, it is desirable to allow the
  400. * user to cancel the session. To provide this alternate means of exit,
  401. * the programmer can call <i>V_intrpt_ok()</i> before <i>V_call()</i>.
  402. * This allows the user to enter CTRL-C, which causes <i>V_call()</i> to
  403. * return a value of 0 instead of 1.<br>
  404. * A message is automatically supplied to the user on line 23 saying to
  405. * use CTRL-C to cancel the input session. The normal message
  406. * accompanying <i>V_call()</i> is moved up to line 22.<br>
  407. * <b>Note:</b> When <i>V_intrpt_ok()</i> is called, the programmer must
  408. * limit the use of <i>V_line()</i>, <i>V_ques()</i>, and
  409. * <i>V_const()</i> to lines 0-21.
  410. *
  411. * \return always returns 0
  412. */
  413. void V_intrpt_ok(void)
  414. {
  415. interrupts_ok = 1; /* will be set false when V_call() exists */
  416. }
  417. /**
  418. * \fn int V_intrpt_msg (const char *msg)
  419. *
  420. * \brief Change CTRL-C message.
  421. *
  422. * A call to <i>V_intrpt_msg()</i> changes the default
  423. * <i>V_intrpt_ok()</i> message from (OR <CTRL-C> TO CANCEL) to (OR
  424. * <CTRL-C> TO <i>msg</i>). The message is (re)set to the default by
  425. * <i>V_clear()</i>.
  426. *
  427. * \param[in] msg
  428. * \return always returns 0
  429. */
  430. void V_intrpt_msg(const char *msg)
  431. {
  432. strcpy (V__.interrupt_msg, msg);
  433. }
  434. static void fmt(char *s,int n, double x)
  435. {
  436. char buf[20];
  437. if (n >= 0)
  438. sprintf (buf, "%%.%dlf", n);
  439. else
  440. strcpy (buf, "%.5lf");
  441. /* I had to use .5lf instead of just lf since a number like 65.8 got
  442. * sprintf'ed as 65.800003 this is a hack - I admit it.
  443. */
  444. sprintf (s, buf, x);
  445. if (n < 0)
  446. V__trim_decimal(s);
  447. }
  448. static void centered(const char *msg)
  449. {
  450. int indent;
  451. indent = (80 - strlen(msg))/2;
  452. while (indent-- > 0)
  453. addstr(" ");
  454. addstr(msg);
  455. addstr("\n");
  456. }