executable_map.cc 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // The definition of the Executable_map class, which defines the mapping
  2. // between executable names and Executable objects. It takes an Argm as
  3. // its key so that it can return argument functions which are part of the Argm
  4. // object.
  5. //
  6. // Copyright (C) 2005-2019 Samuel Newbold
  7. #include <list>
  8. #include <map>
  9. #include <set>
  10. #include <string>
  11. #include <vector>
  12. #include "arg_spec.h"
  13. #include "rwsh_stream.h"
  14. #include "variable_map.h"
  15. #include "argm.h"
  16. #include "arg_script.h"
  17. #include "call_stack.h"
  18. #include "executable.h"
  19. #include "executable_map.h"
  20. #include "prototype.h"
  21. #include "tokenize.cc"
  22. #include "function.h"
  23. Executable_map::Executable_map(void) : in_autofunction(false) {}
  24. // insert target into map, with key target->name(), replacing old value if key
  25. // is already in the map
  26. void Executable_map::set(Named_executable* target) {
  27. std::pair<iterator, bool> ret;
  28. ret = insert(std::make_pair(target->name(), target));
  29. if (!ret.second) { // replace if key already exists
  30. if (!ret.first->second->is_running()) delete ret.first->second;
  31. else ret.first->second->del_on_term = true;
  32. Base::erase(ret.first);
  33. insert(std::make_pair(target->name(), target));}}
  34. Executable_map::size_type Executable_map::erase (const std::string& key) {
  35. iterator pos = Base::find(key);
  36. if (pos == end()) return 0;
  37. else {
  38. if (!pos->second->is_running()) delete pos->second;
  39. else pos->second->del_on_term = true;
  40. Base::erase(pos);
  41. return 1;}}
  42. Base_executable* Executable_map::find_second(const Argm& key) {
  43. iterator i = Base::find(key[0]);
  44. if (i != end()) return i->second;
  45. else if (key[0] == ".mapped_argfunction") return key.argfunction();
  46. else return nullptr;}
  47. bool Executable_map::run_if_exists(const std::string& key, Argm& argm_i) {
  48. Argm temp_argm(key, argm_i.argv(), argm_i.argfunction(),
  49. argm_i.parent_map(), argm_i.input,argm_i.output, argm_i.error);
  50. Base_executable* i = find_second(temp_argm);
  51. if (i) {
  52. Error_list exceptions;
  53. (*i)(temp_argm, exceptions);
  54. if (global_stack.unwind_stack())
  55. global_stack.exception_handler(exceptions);
  56. return true;}
  57. else {
  58. return false;}}
  59. void Executable_map::base_run(Argm& argm, Error_list& exceptions) {
  60. run(argm, exceptions);
  61. if (gc_state.in_if_block && !gc_state.exception_thrown) {
  62. gc_state.in_if_block = false;
  63. exceptions.add_error(Exception(Argm::Unfinished_if_block));}
  64. if (global_stack.unwind_stack())
  65. global_stack.exception_handler(exceptions);}
  66. void Executable_map::run_handling_exceptions(Argm& argm,
  67. Error_list& exceptions) {
  68. run(argm, exceptions);
  69. if (global_stack.unwind_stack())
  70. global_stack.exception_handler(exceptions);}
  71. void Executable_map::unused_var_check_at_exit(void) {
  72. Error_list exceptions;
  73. Prototype shell_invocation;
  74. shell_invocation.unused_var_check(Variable_map::global_map, exceptions);
  75. if (exceptions.size()) global_stack.exception_handler(exceptions);}
  76. void Executable_map::run(Argm& argm, Error_list& exceptions) {
  77. try {
  78. Base_executable* i = find_second(argm); // first check for key
  79. if (i) (*i)(argm, exceptions);
  80. else if (in_autofunction) // nested autofunction
  81. not_found(argm, exceptions);
  82. else {
  83. in_autofunction = true;
  84. Argm auto_argm(Argm::exception_names[Argm::Autofunction], argm.argv(),
  85. argm.argfunction(), argm.parent_map(),
  86. argm.input, argm.output, argm.error);
  87. run(auto_argm, exceptions);
  88. in_autofunction = false;
  89. i = find_second(argm); // second check for key
  90. if (i) (*i)(argm, exceptions);
  91. else not_found(argm, exceptions);}}
  92. catch (Exception error) {
  93. exceptions.add_error(error);}}
  94. bool Executable_map::run_condition(Argm& argm, Error_list& exceptions) {
  95. run(argm, exceptions);
  96. return !global_stack.remove_exceptions(".false", exceptions) &&
  97. !exceptions.size();} // optional
  98. void Executable_map::not_found(Argm& argm_i, Error_list& exceptions) {
  99. if (Base::find(Argm::exception_names[Argm::Function_not_found]) == end()) {
  100. Argm prototype_argm(argm_i.parent_map(), argm_i.input, argm_i.output,
  101. argm_i.error);
  102. tokenize_words("cmd [args ...]", std::back_inserter(prototype_argm));
  103. std::string::size_type point = 0;
  104. Command_block body("{.echo $cmd (: command not found) "
  105. "\\( $cmd $args$ \\); .echo (\n)}",
  106. point, 0, exceptions);
  107. set(new Function(Argm::exception_names[Argm::Function_not_found],
  108. prototype_argm.argv(), body));}
  109. throw Exception(Argm::Function_not_found, argm_i);}