history.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /******************************************************************************
  2. * This file is part of TinTin++ *
  3. * *
  4. * Copyright 2004-2020 Igor van den Hoven *
  5. * *
  6. * TinTin++ 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 3 of the License, or *
  9. * (at your option) any later version. *
  10. * *
  11. * This program is distributed in the hope that it will be useful, *
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  14. * GNU General Public License for more details. *
  15. * *
  16. * You should have received a copy of the GNU General Public License *
  17. * along with TinTin++. If not, see https://www.gnu.org/licenses. *
  18. ******************************************************************************/
  19. /******************************************************************************
  20. * T I N T I N + + *
  21. * *
  22. * coded by Igor van den Hoven 2006 *
  23. ******************************************************************************/
  24. #include "tintin.h"
  25. DO_COMMAND(do_history)
  26. {
  27. int cnt;
  28. arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
  29. if (*arg1 == 0)
  30. {
  31. info:
  32. tintin_header(ses, 80, " HISTORY COMMANDS ");
  33. for (cnt = 0 ; *history_table[cnt].name != 0 ; cnt++)
  34. {
  35. tintin_printf2(ses, " [%-13s] %s", history_table[cnt].name, history_table[cnt].desc);
  36. }
  37. tintin_header(ses, 80, "");
  38. return ses;
  39. }
  40. for (cnt = 0 ; *history_table[cnt].name ; cnt++)
  41. {
  42. if (!is_abbrev(arg1, history_table[cnt].name))
  43. {
  44. continue;
  45. }
  46. history_table[cnt].fun(ses, arg, arg2, arg3);
  47. return ses;
  48. }
  49. goto info;
  50. return ses;
  51. }
  52. void add_line_history(struct session *ses, char *line)
  53. {
  54. struct listroot *root;
  55. int last;
  56. root = ses->list[LIST_HISTORY];
  57. if (HAS_BIT(root->flags, LIST_FLAG_IGNORE) || gtd->level->ignore)
  58. {
  59. return;
  60. }
  61. // avoid infinite loops
  62. if (*line == gtd->repeat_char)
  63. {
  64. return;
  65. }
  66. last = root->used;
  67. update_node_list(ses->list[LIST_HISTORY], line, "", "", "");
  68. if (last < root->used)
  69. {
  70. SET_BIT(gtd->flags, TINTIN_FLAG_HISTORYUPDATE);
  71. }
  72. while (root->used > gtd->history_size)
  73. {
  74. delete_index_list(ses->list[LIST_HISTORY], 0);
  75. }
  76. return;
  77. }
  78. struct session *repeat_history(struct session *ses, char *line)
  79. {
  80. struct listroot *root = ses->list[LIST_HISTORY];
  81. int i;
  82. for (i = root->used - 1 ; i >= 0 ; i--)
  83. {
  84. if (!strncmp(root->list[i]->arg1, line, strlen(line)))
  85. {
  86. add_line_history(gtd->ses, root->list[i]->arg1);
  87. gtd->level->repeat++;
  88. ses = script_driver(ses, LIST_COMMAND, root->list[root->used - 1]->arg1);
  89. gtd->level->repeat--;
  90. return ses;
  91. }
  92. }
  93. tintin_printf2(ses, "#REPEAT: NO MATCH FOUND FOR '%s'", line);
  94. return ses;
  95. }
  96. DO_HISTORY(history_character)
  97. {
  98. arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
  99. gtd->repeat_char = *arg1;
  100. show_message(ses, LIST_HISTORY, "#HISTORY CHARACTER SET TO {%c}.", gtd->repeat_char);
  101. }
  102. DO_HISTORY(history_delete)
  103. {
  104. if (ses->list[LIST_HISTORY]->used)
  105. {
  106. delete_index_list(ses->list[LIST_HISTORY], ses->list[LIST_HISTORY]->used - 1);
  107. }
  108. return;
  109. }
  110. DO_HISTORY(history_insert)
  111. {
  112. arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
  113. add_line_history(ses, arg1);
  114. }
  115. DO_HISTORY(history_get)
  116. {
  117. struct listroot *root = ses->list[LIST_HISTORY];
  118. char *arg3;
  119. int cnt, min, max;
  120. arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
  121. if (*arg1 == 0)
  122. {
  123. show_error(ses, LIST_COMMAND, "#SYNTAX: #HISTORY GET <VARIABLE> [LOWER BOUND] [UPPER BOUND]");
  124. return;
  125. }
  126. arg = get_arg_in_braces(ses, arg, arg2, GET_ONE);
  127. min = get_number(ses, arg2);
  128. if (min < 0)
  129. {
  130. min = root->used + min;
  131. }
  132. min = URANGE(0, min, root->used - 1);
  133. arg3 = str_alloc_stack(0);
  134. arg = sub_arg_in_braces(ses, arg, arg3, GET_ONE, SUB_VAR|SUB_FUN);
  135. if (*arg3 == 0)
  136. {
  137. substitute(ses, root->list[min]->arg1, arg3, SUB_SEC);
  138. set_nest_node_ses(ses, arg1, "%s", arg3);
  139. return;
  140. }
  141. max = get_number(ses, arg3);
  142. if (max < 0)
  143. {
  144. max = root->used + max;
  145. }
  146. max = URANGE(0, max, root->used - 1);
  147. if (min > max)
  148. {
  149. show_error(ses, LIST_COMMAND, "#ERROR: #HISTORY GET {%s} {%d} {%d} LOWER BOUND EXCEEDS UPPER BOUND.", arg1, min, max);
  150. return;
  151. }
  152. cnt = 0;
  153. set_nest_node_ses(ses, arg1, "");
  154. while (min <= max)
  155. {
  156. sprintf(arg2, "%s[%d]", arg1, ++cnt);
  157. substitute(ses, root->list[min++]->arg1, arg3, SUB_SEC);
  158. set_nest_node_ses(ses, arg2, "%s", arg3);
  159. }
  160. show_message(ses, LIST_COMMAND, "#HISTORY GET: %d LINES SAVED TO {%s}.", cnt, arg1);
  161. return;
  162. }
  163. DO_HISTORY(history_list)
  164. {
  165. arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
  166. if (*arg1 == 0)
  167. {
  168. show_list(ses->list[LIST_HISTORY], 0);
  169. }
  170. else
  171. {
  172. show_node_with_wild(ses, arg1, ses->list[LIST_HISTORY]);
  173. }
  174. return;
  175. }
  176. DO_HISTORY(history_read)
  177. {
  178. struct listroot *root = ses->list[LIST_HISTORY];
  179. FILE *file;
  180. arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
  181. file = fopen(arg1, "r");
  182. if (file == NULL)
  183. {
  184. show_message(ses, LIST_HISTORY, "#HISTORY: COULDN'T OPEN FILE {%s} TO READ.", arg1);
  185. return;
  186. }
  187. kill_list(root);
  188. while (fread_one_line(&arg2, file))
  189. {
  190. if (*arg2)
  191. {
  192. create_node_list(root, arg2, "", "", "");
  193. }
  194. }
  195. create_node_list(root, "", "", "", "");
  196. fclose(file);
  197. if (ses->list[LIST_HISTORY]->used > gtd->history_size)
  198. {
  199. command(gts, do_configure, "{HISTORY SIZE} {%d}", UMIN(ses->list[LIST_HISTORY]->used, 9999));
  200. }
  201. return;
  202. }
  203. DO_HISTORY(history_size)
  204. {
  205. arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
  206. if (atoi(arg1) < 1 || atoi(arg1) > 100000)
  207. {
  208. show_error(ses, LIST_COMMAND, "#ERROR: #HISTORY SIZE: PROVIDE A NUMBER BETWEEN 1 and 100,000");
  209. }
  210. else
  211. {
  212. gtd->history_size = atoi(arg1);
  213. }
  214. return;
  215. }
  216. DO_HISTORY(history_write)
  217. {
  218. struct listroot *root = ses->list[LIST_HISTORY];
  219. FILE *file;
  220. int i;
  221. arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
  222. file = fopen(arg1, "w");
  223. if (file == NULL)
  224. {
  225. tintin_printf2(ses, "#HISTORY: COULDN'T OPEN FILE {%s} TO WRITE.", arg1);
  226. return;
  227. }
  228. for (i = 0 ; i < root->used ; i++)
  229. {
  230. fprintf(file, "%s\n", root->list[i]->arg1);
  231. }
  232. fclose(file);
  233. return;
  234. }