nav.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /** @file nav.c
  2. * @brief Navigation
  3. *
  4. * Example:
  5. * <ACTION sym="nav">
  6. * pop
  7. * push /view_name
  8. * </ACTION>
  9. *
  10. * Possible navigation commands:
  11. * * push <view_name> - Push "view_name" view to new level of path and change
  12. * current path to it.
  13. * * pop [num] - Pop up path levels. Optional "num" argument specifies number
  14. * of levels to pop. Default is 1.
  15. * * top - Pop up to first path level.
  16. * * exit - Exit klish.
  17. */
  18. #include <assert.h>
  19. #include <stdio.h>
  20. #include <unistd.h>
  21. #include <string.h>
  22. #include <stdlib.h>
  23. #include <errno.h>
  24. #include <faux/str.h>
  25. #include <faux/list.h>
  26. #include <faux/conv.h>
  27. #include <klish/kcontext.h>
  28. #include <klish/kentry.h>
  29. #include <klish/ksession.h>
  30. #include <klish/kpath.h>
  31. #include <klish/kscheme.h>
  32. int klish_nav(kcontext_t *context)
  33. {
  34. const char *script = NULL;
  35. ksession_t *session = NULL;
  36. kpath_t *path = NULL;
  37. const char *str = NULL;
  38. char *line = NULL;
  39. // Navigation is suitable only for command actions but not for
  40. // PTYPEs, CONDitions i.e. SERVICE_ACTIONS.
  41. assert(kcontext_type(context) == KCONTEXT_ACTION);
  42. script = kcontext_script(context);
  43. if (faux_str_is_empty(script)) // No navigation commands. It's not an error.
  44. return 0;
  45. session = kcontext_session(context);
  46. assert(session);
  47. path = ksession_path(session);
  48. // Iterate lines from "script". Each line is navigation command.
  49. str = script;
  50. while ((line = faux_str_getline(str, &str))) {
  51. faux_argv_t *argv = faux_argv_new();
  52. ssize_t lnum = faux_argv_parse(argv, line);
  53. const char *nav_cmd = NULL;
  54. faux_str_free(line);
  55. if (lnum < 1) {
  56. faux_argv_free(argv);
  57. continue;
  58. }
  59. nav_cmd = faux_argv_index(argv, 0);
  60. // exit
  61. if (faux_str_casecmp(nav_cmd, "exit") == 0) {
  62. ksession_set_done(session, BOOL_TRUE);
  63. // "Exit" supposes another navigation commands have no
  64. // meaning. So break the loop.
  65. faux_argv_free(argv);
  66. break;
  67. // top
  68. } else if (faux_str_casecmp(nav_cmd, "top") == 0) {
  69. while (kpath_len(path) > 1) {
  70. if (!kpath_pop(path)) {
  71. faux_argv_free(argv);
  72. return -1;
  73. }
  74. }
  75. // pop [number_of_levels]
  76. } else if (faux_str_casecmp(nav_cmd, "pop") == 0) {
  77. size_t i = 0;
  78. size_t lnum = 1; // Default levels to pop
  79. const char *lnum_str = faux_argv_index(argv, 1);
  80. // Level number is specified
  81. if (lnum_str) {
  82. unsigned char val = 0;
  83. // 8 bit unsigned integer is enough
  84. if (!faux_conv_atouc(lnum_str, &val, 0)) {
  85. faux_argv_free(argv);
  86. return -1;
  87. }
  88. lnum = val;
  89. }
  90. // Don't pop upper than top level
  91. // Such "pop" means exit
  92. if (lnum > (kpath_len(path) - 1)) {
  93. ksession_set_done(session, BOOL_TRUE);
  94. faux_argv_free(argv);
  95. break;
  96. }
  97. // Pop levels
  98. for (i = 0; i < lnum; i++) {
  99. if (!kpath_pop(path)) {
  100. faux_argv_free(argv);
  101. return -1;
  102. }
  103. }
  104. // push <view_name>
  105. } else if (faux_str_casecmp(nav_cmd, "push") == 0) {
  106. const char *view_name = faux_argv_index(argv, 1);
  107. kentry_t *new_view = NULL;
  108. if (!view_name) {
  109. faux_argv_free(argv);
  110. return -1;
  111. }
  112. new_view = kscheme_find_entry_by_path(
  113. ksession_scheme(session), view_name);
  114. if (!new_view) {
  115. faux_argv_free(argv);
  116. return -1;
  117. }
  118. if (!kpath_push(path, klevel_new(new_view))) {
  119. faux_argv_free(argv);
  120. return -1;
  121. }
  122. // Unknown command
  123. } else {
  124. faux_argv_free(argv);
  125. return -1;
  126. }
  127. faux_argv_free(argv);
  128. }
  129. return 0;
  130. }