ask.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. /****************************************************************
  2. * These routines prompt the user for names of GIS data files
  3. *
  4. * G_ask_new (prompt, name, element, desc)
  5. * G_ask_old (prompt, name, element, desc)
  6. * G_ask_any (prompt, name, element, desc, warn)
  7. * G_ask_in_mapset (prompt, name, element, desc)
  8. * G_ask_new_file (prompt, name, element, desc)
  9. * G_ask_old_file (prompt, name, element, desc)
  10. *
  11. * G_ask_new_ext (prompt, name, element, desc, option, lister)
  12. * G_ask_old_ext (prompt, name, element, desc, option, lister)
  13. * G_ask_any_ext (prompt, name, element, desc, warn, option, lister)
  14. * G_ask_in_mapset_ext (prompt, name, element, desc, option, lister)
  15. *
  16. * char *prompt prompt to be printed. can be "" in which
  17. * case an appropriate prompt will be printed.
  18. * char *name buffer to hold the name input by the user
  19. * char *element GIS data element - "cell", "vect", etc.
  20. * char *desc a description of element. Used for prompting
  21. * and listing. Will be set to element if given as ""
  22. * (eg, if element is "vect", set desc = "vector")
  23. * char *option list option. a description of the option.
  24. * (eg, "with utms" will prompt as follows:
  25. * list -f for a list with utms)
  26. * int (*lister)() subroutine to return text for -f option.
  27. *
  28. *
  29. * G_ask_new() requires the user to enter the name of a file
  30. * which does not exist in the current mapset
  31. * (but which may exist in other mapsets).
  32. *
  33. * G_ask_old() requires the user to enter the name of a file
  34. * which already exists.
  35. *
  36. * G_ask_in_mapset() requires the user to enter the name of a file
  37. * which exists in the current mapset
  38. *
  39. * G_ask_any() accepts any legal filename. Optionally warns user
  40. * if the file exists in the current mapset.
  41. *
  42. * G_ask_new_file() requires the user to enter the name of a new file.
  43. *
  44. * G_ask_old_file() requires the user to enter the name of any existing file.
  45. *
  46. * returns:
  47. * char * mapset where file was found, or
  48. * mapset where file is to be created
  49. * NULL user hit RETURN to cancel the request
  50. *
  51. * note:
  52. * These routines have a 'list' function built in. If a list -f
  53. * option is also desired, create a lister() routine, and
  54. * use G_ask_xxx_ext(). The lister() routine will be called as
  55. * follows:
  56. *
  57. * lister (name, mapset, buf)
  58. *
  59. * char *name name of file
  60. * char *mapset mapset to where file lives
  61. * char *buf buffer to hold description.
  62. * lister() should copy into buf.
  63. * buf will be large (about 400 bytes)
  64. * but only first 60 chars will be displayed
  65. *
  66. *
  67. * for each mapset, lister() will be called once with
  68. * name set to the empty string "" in order to get an title for the
  69. * list. Set buf to null to suppress title, otherwise copy title
  70. * into buf. The title will start above the text for the files.
  71. *
  72. * then for each file in each mapset, lister() will be called
  73. * to obtain infomation about the file.
  74. *
  75. * also:
  76. * G_set_ask_return_msg (msg) char *msg;
  77. * can be used to change the hit RETURN to cancel request message
  78. * displayed during the ask prompting.
  79. *
  80. * G_get_ask_return_msg() will return the msg.
  81. ******************************************************************/
  82. #include <string.h>
  83. #include <stdlib.h>
  84. #include <unistd.h>
  85. #include <grass/gis.h>
  86. #include <grass/glocale.h>
  87. /*
  88. * OLD references any mapset
  89. * NEW, ANY, PRJ are for the current mapset only
  90. *
  91. * OLD means must exist in some mapset
  92. * NEW means must not exist in current mapset
  93. * ANY means just get a name. If file exists, (optionally) warn user.
  94. * PRJ means must exist in current mapset
  95. */
  96. #define OLD 0
  97. #define NEW 1
  98. #define PRJ 2
  99. #define ANY 3
  100. #define ANY_NW 4
  101. #define OLD_FILE 5
  102. #define NEW_FILE 6
  103. static char *ask_return_msg = 0;
  104. static char clear_return_msg = 0;
  105. static int (*no_lister) () = 0;
  106. static int parselist(const char *, int, char *);
  107. static char *ask(const char *, char *, char *, char *, char *, int (*)(),
  108. int);
  109. /*!
  110. * \brief prompt for new database file
  111. *
  112. * The user is asked to enter the name of
  113. * a new file which does not exist in the current mapset.
  114. * <b>Note.</b> The file chosen by the user may exist in other mapsets. This
  115. * routine does not look in other mapsets, since the assumption is that
  116. * <b>name</b> will be used to create a new file. New files are always created
  117. * in the current mapset.
  118. *
  119. * \param prompt
  120. * \param name
  121. * \param element
  122. * \param desc
  123. * \return char *
  124. */
  125. char *G_ask_new(const char *prompt, char *name, char *element, char *desc)
  126. {
  127. return ask(prompt, name, element, desc, (char *)NULL, no_lister, NEW);
  128. }
  129. char *G_ask_new_ext(const char *prompt, char *name, char *element, char *desc,
  130. char *option, int (*lister) ())
  131. {
  132. return ask(prompt, name, element, desc, option, lister, NEW);
  133. }
  134. /*!
  135. * \brief prompt for existing database file
  136. *
  137. * The user is asked to enter the
  138. * name of an existing database file.
  139. * <b>Note.</b> This routine looks for the file in the current mapset as well
  140. * as other mapsets. The mapsets that are searched are determined from the user's
  141. * mapset search path. See Mapset_Search_Path for some more details
  142. * about the search path.
  143. *
  144. * \param prompt
  145. * \param name
  146. * \param element
  147. * \param label
  148. * \return char *
  149. */
  150. char *G_ask_old(const char *prompt, char *name, char *element, char *desc)
  151. {
  152. return ask(prompt, name, element, desc, (char *)NULL, no_lister, OLD);
  153. }
  154. char *G_ask_old_ext(const char *prompt, char *name, char *element, char *desc,
  155. char *option, int (*lister) ())
  156. {
  157. return ask(prompt, name, element, desc, option, lister, OLD);
  158. }
  159. /*!
  160. * \brief prompt for any valid file name
  161. *
  162. * The user is asked to enter
  163. * any leg al file name. If <b>warn</b> is 1 and the file chosen exists in the
  164. * current mapset, then the user is asked if it is ok to overwrite the file. If
  165. * <b>warn</b> is 0, then any leg al name is accepted and no warning is issued
  166. * to the user if the file exists.
  167. *
  168. * \param prompt
  169. * \param name
  170. * \param element
  171. * \param label
  172. * \param warn
  173. * \return char *
  174. */
  175. char *G_ask_any(const char *prompt, char *name, char *element, char *desc,
  176. int warn)
  177. {
  178. return ask(prompt, name, element, desc, (char *)NULL, no_lister,
  179. warn ? ANY : ANY_NW);
  180. }
  181. char *G_ask_any_ext(const char *prompt, char *name, char *element, char *desc,
  182. int warn, char *option, int (*lister) ())
  183. {
  184. return ask(prompt, name, element, desc, option, lister,
  185. warn ? ANY : ANY_NW);
  186. }
  187. /*!
  188. * \brief prompt for existing database file
  189. *
  190. * The user is asked to enter the
  191. * name of an file which exists in the current mapset.
  192. * <b>Note.</b> The file chosen by the user may or may not exist in other
  193. * mapsets. This routine does not look in other mapsets, since the assumption is
  194. * that <b>name</b> will be used to modify a file. GRASS only permits users to
  195. * modify files in the current mapset.
  196. *
  197. * \param prompt
  198. * \param name
  199. * \param element
  200. * \param label
  201. * \return char *
  202. */
  203. char *G_ask_in_mapset(const char *prompt, char *name, char *element,
  204. char *desc)
  205. {
  206. return ask(prompt, name, element, desc, (char *)NULL, no_lister, PRJ);
  207. }
  208. char *G_ask_in_mapset_ext(const char *prompt, char *name, char *element,
  209. char *desc, char *option, int (*lister) ())
  210. {
  211. return ask(prompt, name, element, desc, option, lister, PRJ);
  212. }
  213. /*!
  214. * \brief prompt for new file
  215. *
  216. * The user is asked to enter the name of an file which doesn't exist.
  217. *
  218. * \param prompt
  219. * \param name
  220. * \param element
  221. * \param label
  222. * \return char *
  223. */
  224. char *G_ask_new_file(const char *prompt, char *name, char *element,
  225. char *desc)
  226. {
  227. /* element is a dummy parameter for this function */
  228. return ask(prompt, name, element, desc, (char *)NULL, no_lister,
  229. NEW_FILE);
  230. }
  231. /* do we need this function?
  232. char *
  233. G_ask_new_file_ext (prompt, name, element, desc, option, lister)
  234. char *prompt;
  235. char *name;
  236. char *element;
  237. char *desc;
  238. char *option;
  239. int (*lister)();
  240. {
  241. return ask (prompt, name, element, desc, option, lister, NEW_FILE);
  242. }
  243. */
  244. /*!
  245. * \brief prompt for existing file
  246. *
  247. * The user is asked to enter the name of an file which exists.
  248. *
  249. * \param prompt
  250. * \param name
  251. * \param element
  252. * \param label
  253. * \return char *
  254. */
  255. char *G_ask_old_file(const char *prompt, char *name, char *element,
  256. char *desc)
  257. {
  258. /* element is a dummy parameter for this function */
  259. return ask(prompt, name, element, desc, (char *)NULL, no_lister,
  260. OLD_FILE);
  261. }
  262. /* do we need this function?
  263. char *
  264. G_ask_old_file_ext (prompt, name, element, desc, option, lister)
  265. char *prompt;
  266. char *name;
  267. char *element;
  268. char *desc;
  269. char *option;
  270. int (*lister)();
  271. {
  272. return ask (prompt, name, element, desc, option, lister, OLD_FILE);
  273. }
  274. */
  275. /*!
  276. * \brief set Hit RETURN msg
  277. *
  278. * The "Hit
  279. * RETURN to cancel request" part of the prompt in the prompting routines
  280. * described above, is modified to "Hit RETURN <b>msg.</b>"
  281. *
  282. * \param msg
  283. * \return int
  284. */
  285. int G_set_ask_return_msg(const char *msg)
  286. {
  287. if (ask_return_msg)
  288. G_free(ask_return_msg);
  289. ask_return_msg = G_store(msg);
  290. clear_return_msg = 0;
  291. return 0;
  292. }
  293. /*!
  294. * \brief get Hit RETURN msg
  295. *
  296. * The current
  297. * <i>msg</i> (as set by <i>G_set_ask_return_msg</i>) is returned.
  298. *
  299. * \param void
  300. * \return char *
  301. */
  302. char *G_get_ask_return_msg()
  303. {
  304. static char none[80];
  305. strcpy(none, _("to cancel request"));
  306. return (ask_return_msg == NULL ? none : ask_return_msg);
  307. }
  308. static char *ask(const char *prompt,
  309. char *name,
  310. char *element,
  311. char *desc, char *option, int (*lister) (), int type)
  312. {
  313. char tmapset[GMAPSET_MAX];
  314. char xname[GNAME_MAX], xmapset[GMAPSET_MAX];
  315. int name_is_qualified;
  316. int ok;
  317. char tprompt[256];
  318. char input[256];
  319. char *mapset;
  320. char *cur_mapset;
  321. G__check_gisinit();
  322. fflush(stdout);
  323. /* RETURN msg */
  324. if (clear_return_msg) {
  325. G_free(ask_return_msg);
  326. ask_return_msg = 0;
  327. }
  328. clear_return_msg = ask_return_msg ? 1 : 0;
  329. /* make sure option is valid */
  330. if (lister && (option == 0 || *option == 0))
  331. lister = 0;
  332. /* set name to NO NAME at outset */
  333. *name = 0;
  334. /*
  335. * if element description not given, make it the same as the
  336. * element name
  337. */
  338. if (desc == 0 || *desc == 0)
  339. desc = element;
  340. /*
  341. * if no prompt is given, build an approriate prompt
  342. */
  343. if (prompt == 0 || *prompt == 0) {
  344. switch (type) {
  345. case NEW:
  346. case NEW_FILE:
  347. sprintf(tprompt, _("Enter a new %s file name"), desc);
  348. prompt = tprompt;
  349. break;
  350. case OLD:
  351. case PRJ:
  352. case OLD_FILE:
  353. sprintf(tprompt, _("Enter the name of an existing %s file"),
  354. desc);
  355. prompt = tprompt;
  356. break;
  357. default:
  358. sprintf(tprompt, _("Enter %s file name"), desc);
  359. prompt = tprompt;
  360. break;
  361. }
  362. }
  363. /*
  364. * get the current mapset name
  365. */
  366. cur_mapset = G_mapset();
  367. while (1) {
  368. /*
  369. * print the prompt and input the request
  370. */
  371. do {
  372. fprintf(stderr, "\n%s\n", prompt);
  373. /* no listing function implemented for old_file and new_file */
  374. if (type != OLD_FILE && type != NEW_FILE)
  375. fprintf(stderr,
  376. _("Enter 'list' for a list of existing %s files\n"),
  377. desc);
  378. if (lister) {
  379. fprintf(stderr, _("Enter 'list -f' for "));
  380. if (option && *option)
  381. fprintf(stderr, _("a list %s"), option);
  382. else
  383. fprintf(stderr, _("an extended list"));
  384. fprintf(stderr, "\n");
  385. }
  386. fprintf(stderr, _("Hit RETURN %s\n"), G_get_ask_return_msg());
  387. fprintf(stderr, "> ");
  388. }
  389. while (!G_gets(input));
  390. G_strip(input);
  391. fprintf(stderr, "<%s>\n", input);
  392. /*
  393. * if the user just hit return (or blanks only)
  394. * return NULL
  395. */
  396. if (*input == 0)
  397. return 0;
  398. if (type == OLD_FILE || type == NEW_FILE) {
  399. int exist;
  400. exist = (access(input, 0) == 0);
  401. if (type == OLD_FILE && !exist) {
  402. fprintf(stderr, _("\n** %s - not found **\n"), input);
  403. continue;
  404. }
  405. if (type == NEW_FILE && exist) {
  406. char question[200];
  407. sprintf(question,
  408. _("\n** %s exists. ok to overwrite? "), input);
  409. if (!G_yes(question, 0))
  410. continue;
  411. }
  412. strcpy(name, input);
  413. return G_store(input);
  414. }
  415. /*
  416. * 'list' does a list without extension. if we are looking for a new
  417. * file only list the current mapset. Otherwise list all mapsets
  418. * in the mapset search list
  419. *
  420. * 0 not a list request
  421. * 1 list
  422. * 2 list -f
  423. * 3 list mapset
  424. * 4 list -f mapset
  425. */
  426. switch (parselist(input, lister ? 1 : 0, tmapset)) {
  427. case 0:
  428. break;
  429. case 1:
  430. G_list_element(element, desc, type == OLD ? "" : cur_mapset,
  431. no_lister);
  432. continue;
  433. case 2:
  434. G_list_element(element, desc, type == OLD ? "" : cur_mapset,
  435. lister);
  436. continue;
  437. case 3:
  438. G_list_element(element, desc, tmapset, no_lister);
  439. continue;
  440. case 4:
  441. G_list_element(element, desc, tmapset, lister);
  442. continue;
  443. default:
  444. fprintf(stderr, "** illegal request **\n");
  445. continue;
  446. }
  447. if ((name_is_qualified =
  448. G__name_is_fully_qualified(input, xname, xmapset)))
  449. ok = G_legal_filename(xname) >= 0;
  450. else
  451. ok = G_legal_filename(input) >= 0;
  452. if (!ok) {
  453. fprintf(stderr, _("\n**<%s> illegal name **\n"), input);
  454. continue;
  455. }
  456. /*
  457. * now look for the file.
  458. *
  459. * new files must be simple names
  460. * and must not exist in the current mapset
  461. */
  462. if (type != OLD) {
  463. if (name_is_qualified) {
  464. if (strcmp(cur_mapset, xmapset) != 0) {
  465. fprintf(stderr, _("\n** %s - illegal request **\n"),
  466. input);
  467. continue;
  468. }
  469. strcpy(input, xname);
  470. }
  471. mapset = G_find_file(element, input, cur_mapset);
  472. switch (type) {
  473. case NEW:
  474. if (!mapset) {
  475. strcpy(name, input);
  476. return cur_mapset;
  477. }
  478. fprintf(stderr,
  479. _("\n** %s - exists, select another name **\n"),
  480. input);
  481. break;
  482. case ANY:
  483. case ANY_NW:
  484. if (mapset && type == ANY) {
  485. char question[200];
  486. sprintf(question,
  487. _("\n** %s exists. ok to overwrite? "), input);
  488. if (!G_yes(question, 0))
  489. break;
  490. }
  491. strcpy(name, input);
  492. return cur_mapset;
  493. case PRJ:
  494. if (mapset) {
  495. strcpy(name, input);
  496. return cur_mapset;
  497. }
  498. fprintf(stderr, _("\n** %s - not found **\n"), input);
  499. break;
  500. default:
  501. G_fatal_error(_("ask: can't happen"));
  502. }
  503. }
  504. /*
  505. * old names can be simple or qualified
  506. * and must exist
  507. */
  508. else {
  509. mapset = G_find_file(element, input, "");
  510. if (mapset) {
  511. if (name_is_qualified)
  512. strcpy(name, xname);
  513. else
  514. strcpy(name, input);
  515. return mapset;
  516. }
  517. fprintf(stderr, _("\n** %s - not found **\n"), input);
  518. }
  519. }
  520. return NULL;
  521. }
  522. static int parselist(const char *input, int option, char *mapset)
  523. {
  524. char list[GNAME_MAX];
  525. char f1[GMAPSET_MAX];
  526. char f2[GMAPSET_MAX];
  527. char f3[GMAPSET_MAX];
  528. int count;
  529. *list = *f1 = *f2 = 0;
  530. count = sscanf(input, "%s%s%s%s", list, f1, f2, f3);
  531. if (count < 1)
  532. return 0;
  533. if (strcmp(list, "list") != 0)
  534. return 0;
  535. if (count == 1)
  536. return 1; /* list */
  537. if (count > 3)
  538. return -1; /* illegal */
  539. if (*f1 == '-') { /* list -f */
  540. if (!option)
  541. return -1;
  542. if (f1[1] == 0 || f1[1] != 'f' || f1[2] != 0)
  543. return -1;
  544. if (count == 2)
  545. return 2;
  546. strcpy(mapset, f2);
  547. return 4;
  548. }
  549. if (count != 2)
  550. return -1;
  551. strcpy(mapset, f1);
  552. return 3;
  553. }