hooks.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /* $OpenBSD$ */
  2. /*
  3. * Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
  14. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  15. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/types.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include "tmux.h"
  21. struct hooks {
  22. RB_HEAD(hooks_tree, hook) tree;
  23. struct hooks *parent;
  24. };
  25. static int hooks_cmp(struct hook *, struct hook *);
  26. RB_PROTOTYPE(hooks_tree, hook, entry, hooks_cmp);
  27. RB_GENERATE(hooks_tree, hook, entry, hooks_cmp);
  28. static struct hook *hooks_find1(struct hooks *, const char *);
  29. static void hooks_free1(struct hooks *, struct hook *);
  30. static void hooks_emptyfn(struct cmd_q *);
  31. static int
  32. hooks_cmp(struct hook *hook1, struct hook *hook2)
  33. {
  34. return (strcmp(hook1->name, hook2->name));
  35. }
  36. struct hooks *
  37. hooks_get(struct session *s)
  38. {
  39. if (s != NULL)
  40. return (s->hooks);
  41. return (global_hooks);
  42. }
  43. struct hooks *
  44. hooks_create(struct hooks *parent)
  45. {
  46. struct hooks *hooks;
  47. hooks = xcalloc(1, sizeof *hooks);
  48. RB_INIT(&hooks->tree);
  49. hooks->parent = parent;
  50. return (hooks);
  51. }
  52. static void
  53. hooks_free1(struct hooks *hooks, struct hook *hook)
  54. {
  55. RB_REMOVE(hooks_tree, &hooks->tree, hook);
  56. cmd_list_free(hook->cmdlist);
  57. free((char *)hook->name);
  58. free(hook);
  59. }
  60. void
  61. hooks_free(struct hooks *hooks)
  62. {
  63. struct hook *hook, *hook1;
  64. RB_FOREACH_SAFE(hook, hooks_tree, &hooks->tree, hook1)
  65. hooks_free1(hooks, hook);
  66. free(hooks);
  67. }
  68. struct hook *
  69. hooks_first(struct hooks *hooks)
  70. {
  71. return (RB_MIN(hooks_tree, &hooks->tree));
  72. }
  73. struct hook *
  74. hooks_next(struct hook *hook)
  75. {
  76. return (RB_NEXT(hooks_tree, &hooks->tree, hook));
  77. }
  78. void
  79. hooks_add(struct hooks *hooks, const char *name, struct cmd_list *cmdlist)
  80. {
  81. struct hook *hook;
  82. if ((hook = hooks_find1(hooks, name)) != NULL)
  83. hooks_free1(hooks, hook);
  84. hook = xcalloc(1, sizeof *hook);
  85. hook->name = xstrdup(name);
  86. hook->cmdlist = cmdlist;
  87. hook->cmdlist->references++;
  88. RB_INSERT(hooks_tree, &hooks->tree, hook);
  89. }
  90. void
  91. hooks_remove(struct hooks *hooks, const char *name)
  92. {
  93. struct hook *hook;
  94. if ((hook = hooks_find1(hooks, name)) != NULL)
  95. hooks_free1(hooks, hook);
  96. }
  97. static struct hook *
  98. hooks_find1(struct hooks *hooks, const char *name)
  99. {
  100. struct hook hook;
  101. hook.name = name;
  102. return (RB_FIND(hooks_tree, &hooks->tree, &hook));
  103. }
  104. struct hook *
  105. hooks_find(struct hooks *hooks, const char *name)
  106. {
  107. struct hook hook0, *hook;
  108. hook0.name = name;
  109. hook = RB_FIND(hooks_tree, &hooks->tree, &hook0);
  110. while (hook == NULL) {
  111. hooks = hooks->parent;
  112. if (hooks == NULL)
  113. break;
  114. hook = RB_FIND(hooks_tree, &hooks->tree, &hook0);
  115. }
  116. return (hook);
  117. }
  118. static void
  119. hooks_emptyfn(struct cmd_q *hooks_cmdq)
  120. {
  121. struct cmd_q *cmdq = hooks_cmdq->data;
  122. if (cmdq != NULL) {
  123. if (hooks_cmdq->client_exit >= 0)
  124. cmdq->client_exit = hooks_cmdq->client_exit;
  125. if (!cmdq_free(cmdq))
  126. cmdq_continue(cmdq);
  127. }
  128. cmdq_free(hooks_cmdq);
  129. }
  130. int
  131. hooks_run(struct hooks *hooks, struct client *c, struct cmd_find_state *fs,
  132. const char *fmt, ...)
  133. {
  134. struct hook *hook;
  135. struct cmd_q *hooks_cmdq;
  136. va_list ap;
  137. char *name;
  138. va_start(ap, fmt);
  139. xvasprintf(&name, fmt, ap);
  140. va_end(ap);
  141. hook = hooks_find(hooks, name);
  142. if (hook == NULL) {
  143. free(name);
  144. return (-1);
  145. }
  146. log_debug("running hook %s", name);
  147. free(name);
  148. hooks_cmdq = cmdq_new(c);
  149. hooks_cmdq->flags |= CMD_Q_NOHOOKS;
  150. if (fs != NULL)
  151. cmd_find_copy_state(&hooks_cmdq->current, fs);
  152. hooks_cmdq->parent = NULL;
  153. cmdq_run(hooks_cmdq, hook->cmdlist, NULL);
  154. cmdq_free(hooks_cmdq);
  155. return (0);
  156. }
  157. int
  158. hooks_wait(struct hooks *hooks, struct cmd_q *cmdq, struct cmd_find_state *fs,
  159. const char *fmt, ...)
  160. {
  161. struct hook *hook;
  162. struct cmd_q *hooks_cmdq;
  163. va_list ap;
  164. char *name;
  165. va_start(ap, fmt);
  166. xvasprintf(&name, fmt, ap);
  167. va_end(ap);
  168. hook = hooks_find(hooks, name);
  169. if (hook == NULL) {
  170. free(name);
  171. return (-1);
  172. }
  173. log_debug("running hook %s (parent %p)", name, cmdq);
  174. free(name);
  175. hooks_cmdq = cmdq_new(cmdq->client);
  176. hooks_cmdq->flags |= CMD_Q_NOHOOKS;
  177. if (fs != NULL)
  178. cmd_find_copy_state(&hooks_cmdq->current, fs);
  179. hooks_cmdq->parent = cmdq;
  180. hooks_cmdq->emptyfn = hooks_emptyfn;
  181. hooks_cmdq->data = cmdq;
  182. if (cmdq != NULL)
  183. cmdq->references++;
  184. cmdq_run(hooks_cmdq, hook->cmdlist, NULL);
  185. return (0);
  186. }