variables.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. /* variables.c -- how to manipulate user visible variables in Info.
  2. $Id$
  3. Copyright 1993, 1997, 2001, 2002, 2004, 2007, 2008, 2011, 2013,
  4. 2014, 2015, 2017 Free Software Foundation, Inc.
  5. This program is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. Originally written by Brian Fox. */
  16. #include "info.h"
  17. #include "session.h"
  18. #include "echo-area.h"
  19. #include "variables.h"
  20. #include "terminal.h"
  21. #include "display.h"
  22. static VARIABLE_ALIST *read_variable_name (char *prompt, WINDOW *window);
  23. /* **************************************************************** */
  24. /* */
  25. /* User Visible Variables in Info */
  26. /* */
  27. /* **************************************************************** */
  28. /* Choices used by the completer when reading a zero/non-zero value for
  29. a variable. */
  30. static char *on_off_choices[] = { "Off", "On", NULL };
  31. static char *mouse_choices[] = { "Off", "normal-tracking", NULL };
  32. static char *follow_strategy_choices[] = { "remain", "path", NULL };
  33. static char *nodeline_choices[] = { "no", "print", "pointers", NULL };
  34. /* Choices used by the completer when reading a value for the user-visible
  35. variable "scroll-behaviour". */
  36. static char *info_scroll_choices[] = { "Continuous", "Next Only",
  37. "Page Only", NULL };
  38. /* Choices for the scroll-last-node variable */
  39. static char *scroll_last_node_choices[] = { "Stop", "Top", NULL };
  40. /* Choices for, and indicator of, renditions. */
  41. static char *rendition_choices[] = { "black", "red", "green", "yellow", "blue",
  42. "magenta", "cyan", "white", "nocolour", "bgblack", "bgred", "bggreen",
  43. "bgyellow", "bgblue", "bgmagenta", "bgcyan", "bgwhite", "nobgcolour",
  44. "underline", "nounderline", "standout", "nostandout", "bold", "regular",
  45. "blink", "noblink", NULL };
  46. /* Address of this indicates the 'highlight-searches' variable. */
  47. static int *highlight_searches;
  48. /* Note that the 'where_set' field of each element in the array is
  49. not given and defaults to 0. */
  50. VARIABLE_ALIST info_variables[] = {
  51. { "automatic-footnotes",
  52. N_("When \"On\", footnotes appear and disappear automatically"),
  53. &auto_footnotes_p, (char **)on_off_choices },
  54. { "automatic-tiling",
  55. N_("When \"On\", creating or deleting a window resizes other windows"),
  56. &auto_tiling_p, (char **)on_off_choices },
  57. { "visible-bell",
  58. N_("When \"On\", flash the screen instead of ringing the bell"),
  59. &terminal_use_visible_bell_p, (char **)on_off_choices },
  60. { "errors-ring-bell",
  61. N_("When \"On\", errors cause the bell to ring"),
  62. &info_error_rings_bell_p, (char **)on_off_choices },
  63. { "gc-compressed-files",
  64. N_("When \"On\", Info garbage collects files which had to be uncompressed"),
  65. &gc_compressed_files, (char **)on_off_choices },
  66. { "show-index-match",
  67. N_("When \"On\", the portion of the matched search string is highlighted"),
  68. &show_index_match, (char **)on_off_choices },
  69. { "scroll-behaviour",
  70. N_("Controls what happens when scrolling is requested at the end of a node"),
  71. &info_scroll_behaviour, (char **)info_scroll_choices },
  72. /* Alternate spelling */
  73. { "scroll-behavior",
  74. N_("Same as scroll-behaviour"),
  75. &info_scroll_behaviour, (char **)info_scroll_choices },
  76. { "scroll-step",
  77. N_("The number lines to scroll when the cursor moves out of the window"),
  78. &window_scroll_step, NULL },
  79. { "cursor-movement-scrolls",
  80. N_("Controls whether scroll-behavior affects cursor movement commands"),
  81. &cursor_movement_scrolls_p, (char **)on_off_choices },
  82. { "ISO-Latin",
  83. N_("When \"On\", Info accepts and displays ISO Latin characters"),
  84. &ISO_Latin_p, (char **)on_off_choices },
  85. { "scroll-last-node",
  86. N_("What to do when a scrolling command is issued at the end of the "
  87. "last node"),
  88. &scroll_last_node, (char**)scroll_last_node_choices },
  89. { "min-search-length",
  90. N_("Minimal length of a search string"),
  91. &min_search_length, NULL },
  92. { "search-skip-screen",
  93. N_("Skip current window when searching"),
  94. &search_skip_screen_p, (char **)on_off_choices },
  95. { "infopath-no-defaults",
  96. N_("Exclude default directories from file search path"),
  97. &infopath_no_defaults_p, (char **)on_off_choices },
  98. { "hide-note-references",
  99. N_("Hide some Info file syntax in the text of nodes"),
  100. &preprocess_nodes_p, (char **)on_off_choices },
  101. { "key-time",
  102. N_("Length of time in milliseconds to wait for the next byte in a sequence indicating that a key has been pressed"),
  103. &key_time, NULL },
  104. { "mouse",
  105. N_("Method to use to track mouse events"),
  106. &mouse_protocol, (char **)mouse_choices },
  107. { "follow-strategy",
  108. N_("How to follow a cross-reference"),
  109. &follow_strategy, (char **)follow_strategy_choices },
  110. { "highlight-searches",
  111. N_("Highlight search matches"),
  112. &highlight_searches, (char **)on_off_choices },
  113. { "link-style",
  114. N_("Styles for links"),
  115. &ref_rendition, (char **)rendition_choices },
  116. { "active-link-style",
  117. N_("Styles for active links"),
  118. &hl_ref_rendition, (char **)rendition_choices },
  119. { "match-style",
  120. N_("Styles for search matches"),
  121. &match_rendition, (char **)rendition_choices },
  122. { "nodeline",
  123. N_("How to print the information line at the start of a node"),
  124. &nodeline_print, (char **)nodeline_choices },
  125. { NULL }
  126. };
  127. static char *
  128. rendition_to_string (RENDITION *rendition)
  129. {
  130. static char string[8 /* nocolour */ + 1 /* comma */
  131. + 10 /* nobgcolour */ + 1
  132. + 11 /* nounderline */ + 1
  133. + 10 /* nostandout */ + 1
  134. + 7 /* regular */ + 1
  135. + 7 /* noblink */ + 1];
  136. unsigned long style;
  137. static const char* fg[] = { "black", "red", "green", "yellow", "blue",
  138. "magenta", "cyan", "white" };
  139. static const char* bg[] = { "bgblack", "bgred", "bggreen", "bgyellow",
  140. "bgblue", "bgmagenta", "bgcyan", "bgwhite" };
  141. *string = '\0';
  142. if (rendition->mask & BLINK_MASK)
  143. strcat (string, rendition->value & BLINK_MASK ? "blink" : "noblink");
  144. if (rendition->mask & BOLD_MASK)
  145. {
  146. if (*string != '\0')
  147. strcat (string, ",");
  148. strcat (string, rendition->value & BOLD_MASK ? "bold" : "nobold");
  149. }
  150. if (rendition->mask & STANDOUT_MASK)
  151. {
  152. if (*string != '\0')
  153. strcat (string, ",");
  154. strcat (string, rendition->value & STANDOUT_MASK ? "standout" : "nostandout");
  155. }
  156. if (rendition->mask & UNDERLINE_MASK)
  157. {
  158. if (*string != '\0')
  159. strcat (string, ",");
  160. strcat (string, rendition->value & UNDERLINE_MASK ? "underline" : "nounderline");
  161. }
  162. if (rendition->mask & COLOUR_MASK)
  163. {
  164. if (*string != '\0')
  165. strcat (string, ",");
  166. style = rendition->value & COLOUR_MASK;
  167. strcat (string, style >= 8 ? fg[style - 8] : "nocolour");
  168. }
  169. if (rendition->mask & BGCOLOUR_MASK)
  170. {
  171. if (*string != '\0')
  172. strcat (string, ",");
  173. style = (rendition->value & BGCOLOUR_MASK) >> 9;
  174. strcat (string, style >= 8 ? bg[style - 8] : "nobgcolour");
  175. }
  176. return string;
  177. }
  178. DECLARE_INFO_COMMAND (describe_variable, _("Explain the use of a variable"))
  179. {
  180. VARIABLE_ALIST *var;
  181. char *description;
  182. /* Get the variable's name. */
  183. var = read_variable_name (_("Describe variable: "), window);
  184. if (!var)
  185. return;
  186. if (var->choices)
  187. asprintf (&description, "%s (%s): %s.",
  188. var->name,
  189. var->value == &highlight_searches
  190. ? on_off_choices[match_rendition.mask != 0]
  191. : var->choices == (char **) &rendition_choices
  192. ? rendition_to_string (var->value)
  193. : var->choices[*(int *)var->value], _(var->doc));
  194. else
  195. asprintf (&description, "%s (%d): %s.",
  196. var->name, *(int *)var->value, _(var->doc));
  197. window_message_in_echo_area ("%s", description);
  198. free (description);
  199. }
  200. DECLARE_INFO_COMMAND (set_variable, _("Set the value of an Info variable"))
  201. {
  202. VARIABLE_ALIST *var;
  203. char *line;
  204. char prompt[100];
  205. /* Get the variable's name and value. */
  206. var = read_variable_name (_("Set variable: "), window);
  207. if (!var)
  208. return;
  209. /* Read a new value for this variable. */
  210. if (!var->choices)
  211. {
  212. int potential_value;
  213. if (info_explicit_arg || count != 1)
  214. potential_value = count;
  215. else
  216. potential_value = *(int *)(var->value);
  217. sprintf (prompt, _("Set %s to value (%d): "),
  218. var->name, potential_value);
  219. line = info_read_in_echo_area (prompt);
  220. /* User aborted? */
  221. if (!line)
  222. return;
  223. /* If the user specified a value, get that, otherwise, we are done. */
  224. canonicalize_whitespace (line);
  225. set_variable_to_value (var, line, SET_IN_SESSION);
  226. free (line);
  227. }
  228. else
  229. {
  230. register int i;
  231. REFERENCE **array = NULL;
  232. size_t array_index = 0;
  233. size_t array_slots = 0;
  234. for (i = 0; var->choices[i]; i++)
  235. {
  236. REFERENCE *entry;
  237. entry = xmalloc (sizeof (REFERENCE));
  238. entry->label = xstrdup (var->choices[i]);
  239. entry->nodename = NULL;
  240. entry->filename = NULL;
  241. add_pointer_to_array (entry, array_index, array, array_slots, 10);
  242. }
  243. sprintf (prompt, _("Set %s to value (%s): "),
  244. var->name,
  245. var->value == &highlight_searches
  246. ? on_off_choices[match_rendition.mask != 0]
  247. : var->choices == (char **) &rendition_choices
  248. ? rendition_to_string (var->value)
  249. : var->choices[*(int *)(var->value)]);
  250. /* Ask the completer to read a variable value for us. */
  251. if (var->choices == (char **) &rendition_choices)
  252. line = info_read_maybe_completing (prompt, array);
  253. else
  254. line = info_read_completing_in_echo_area (prompt, array);
  255. info_free_references (array);
  256. /* User aborted? */
  257. if (!line)
  258. {
  259. info_abort_key (active_window, 0);
  260. return;
  261. }
  262. /* User accepted default choice? If so, no change. */
  263. if (!*line)
  264. {
  265. free (line);
  266. return;
  267. }
  268. set_variable_to_value (var, line, SET_IN_SESSION);
  269. }
  270. }
  271. VARIABLE_ALIST *
  272. variable_by_name (char *name)
  273. {
  274. int i;
  275. /* Find the variable in our list of variables. */
  276. for (i = 0; info_variables[i].name; i++)
  277. if (strcmp (info_variables[i].name, name) == 0)
  278. break;
  279. if (!info_variables[i].name)
  280. return NULL;
  281. else
  282. return &info_variables[i];
  283. }
  284. /* Read the name of an Info variable in the echo area and return the
  285. address of a VARIABLE_ALIST member. A return value of NULL indicates
  286. that no variable could be read. */
  287. static VARIABLE_ALIST *
  288. read_variable_name (char *prompt, WINDOW *window)
  289. {
  290. char *line;
  291. REFERENCE **variables;
  292. /* Get the completion array of variable names. */
  293. variables = make_variable_completions_array ();
  294. /* Ask the completer to read a variable for us. */
  295. line = info_read_completing_in_echo_area (prompt, variables);
  296. info_free_references (variables);
  297. /* User aborted? */
  298. if (!line)
  299. {
  300. info_abort_key (active_window, 0);
  301. return NULL;
  302. }
  303. /* User accepted "default"? (There is none.) */
  304. if (!*line)
  305. {
  306. free (line);
  307. return NULL;
  308. }
  309. return variable_by_name (line);
  310. }
  311. /* Make an array of REFERENCE which actually contains the names of the
  312. variables available in Info. */
  313. REFERENCE **
  314. make_variable_completions_array (void)
  315. {
  316. register int i;
  317. REFERENCE **array = NULL;
  318. size_t array_index = 0, array_slots = 0;
  319. for (i = 0; info_variables[i].name; i++)
  320. {
  321. REFERENCE *entry;
  322. entry = xmalloc (sizeof (REFERENCE));
  323. entry->label = xstrdup (info_variables[i].name);
  324. entry->nodename = NULL;
  325. entry->filename = NULL;
  326. add_pointer_to_array (entry, array_index, array, array_slots, 200);
  327. }
  328. return array;
  329. }
  330. /* VALUE is a string that is the value of the variable specified
  331. by the user. Update our internal data structure VAR using this
  332. information. */
  333. int
  334. set_variable_to_value (VARIABLE_ALIST *var, char *value, int where)
  335. {
  336. /* If variable was set elsewhere with a higher priority, don't do
  337. anything, but don't indicate an error. */
  338. if (var->where_set > where)
  339. return 1;
  340. if (var->choices)
  341. {
  342. register int j;
  343. /* "highlight-searches=On" is equivalent to
  344. "match-rendition=standout". */
  345. if (var->value == &highlight_searches)
  346. {
  347. if (strcmp (on_off_choices[0], value) == 0)
  348. {
  349. match_rendition.mask = 0;
  350. match_rendition.value = 0;
  351. }
  352. else
  353. {
  354. match_rendition.mask = STANDOUT_MASK;
  355. match_rendition.value = STANDOUT_MASK;
  356. }
  357. }
  358. else if (var->choices != (char **) &rendition_choices)
  359. {
  360. /* Find the choice in our list of choices. */
  361. for (j = 0; var->choices[j]; j++)
  362. if (strcmp (var->choices[j], value) == 0)
  363. {
  364. *(int *)var->value = j;
  365. var->where_set = where;
  366. return 1;
  367. }
  368. }
  369. else
  370. {
  371. static struct {
  372. unsigned long mask;
  373. unsigned long value;
  374. char *name;
  375. } styles[] = {
  376. COLOUR_MASK, COLOUR_BLACK, "black",
  377. COLOUR_MASK, COLOUR_RED, "red",
  378. COLOUR_MASK, COLOUR_GREEN, "green",
  379. COLOUR_MASK, COLOUR_YELLOW, "yellow",
  380. COLOUR_MASK, COLOUR_BLUE, "blue",
  381. COLOUR_MASK, COLOUR_MAGENTA, "magenta",
  382. COLOUR_MASK, COLOUR_CYAN, "cyan",
  383. COLOUR_MASK, COLOUR_WHITE, "white",
  384. COLOUR_MASK, 0, "nocolour",
  385. COLOUR_MASK, 0, "nocolor",
  386. BGCOLOUR_MASK, BGCOLOUR_BLACK, "bgblack",
  387. BGCOLOUR_MASK, BGCOLOUR_RED, "bgred",
  388. BGCOLOUR_MASK, BGCOLOUR_GREEN, "bggreen",
  389. BGCOLOUR_MASK, BGCOLOUR_YELLOW, "bgyellow",
  390. BGCOLOUR_MASK, BGCOLOUR_BLUE, "bgblue",
  391. BGCOLOUR_MASK, BGCOLOUR_MAGENTA, "bgmagenta",
  392. BGCOLOUR_MASK, BGCOLOUR_CYAN, "bgcyan",
  393. BGCOLOUR_MASK, BGCOLOUR_WHITE, "bgwhite",
  394. BGCOLOUR_MASK, 0, "nobgcolour",
  395. BGCOLOUR_MASK, 0, "nobgcolor",
  396. UNDERLINE_MASK, UNDERLINE_MASK, "underline",
  397. UNDERLINE_MASK, 0, "nounderline",
  398. STANDOUT_MASK, STANDOUT_MASK, "standout",
  399. STANDOUT_MASK, 0, "nostandout",
  400. BOLD_MASK, BOLD_MASK, "bold",
  401. BOLD_MASK, 0, "regular",
  402. BOLD_MASK, 0, "nobold",
  403. BLINK_MASK, BLINK_MASK, "blink",
  404. BLINK_MASK, 0, "noblink",
  405. };
  406. int i;
  407. char *component;
  408. unsigned long rendition_mask = 0;
  409. unsigned long rendition_value = 0;
  410. component = strtok (value, ",");
  411. while (component)
  412. {
  413. for (i = 0; (styles[i].name); i++)
  414. {
  415. if (!strcmp (styles[i].name, component))
  416. break;
  417. }
  418. if (styles[i].name)
  419. {
  420. rendition_mask |= styles[i].mask;
  421. rendition_value &= ~styles[i].mask;
  422. rendition_value |= styles[i].value;
  423. }
  424. /* If not found, silently ignore, in case more options are
  425. added in the future. */
  426. component = strtok (0, ",");
  427. }
  428. /* Now all the specified styles are recorded in rendition_value. */
  429. ((RENDITION *)var->value)->mask = rendition_mask;
  430. ((RENDITION *)var->value)->value = rendition_value;
  431. }
  432. return 1;
  433. }
  434. else
  435. {
  436. char *p;
  437. long n = strtol (value, &p, 10);
  438. if (*p == 0 && INT_MIN <= n && n <= INT_MAX)
  439. {
  440. *(int *)var->value = n;
  441. return 1;
  442. }
  443. }
  444. return 0;
  445. }