You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

131 lines
4.0 KiB

  1. /*
  2. * virsh-completer.c: virsh completer callbacks
  3. *
  4. * Copyright (C) 2017 Red Hat, Inc.
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library 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 GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library. If not, see
  18. * <http://www.gnu.org/licenses/>.
  19. */
  20. #include <config.h>
  21. #include "virsh-completer.h"
  22. #include "viralloc.h"
  23. #include "virstring.h"
  24. /**
  25. * A completer callback is a function that accepts three arguments:
  26. *
  27. * @ctl: virsh control structure
  28. * @cmd: parsed input
  29. * @flags: optional flags to alter completer's behaviour
  30. *
  31. * The @ctl contains connection to the daemon (should the
  32. * completer need it). Any completer that requires a connection
  33. * must check whether connection is still alive.
  34. *
  35. * The @cmd contains parsed user input which might be missing
  36. * some arguments (if user is still typing the command), but may
  37. * already contain important data. For instance if the completer
  38. * needs domain XML it may inspect @cmd to find --domain. Using
  39. * existing wrappers is advised. If @cmd does not contain all
  40. * necessary bits, completer might return sensible defaults (i.e.
  41. * generic values not tailored to specific use case) or return
  42. * NULL (i.e. no strings are offered to the user for completion).
  43. *
  44. * The @flags contains a .completer_flags value defined for each
  45. * use or 0 if no .completer_flags were specified. If a completer
  46. * is generic enough @flags can be used to alter its behaviour.
  47. * For instance, a completer to fetch names of domains can use
  48. * @flags to return names of only domains in a particular state
  49. * that the command accepts.
  50. *
  51. * Under no circumstances should a completer output anything.
  52. * Neither to stdout nor to stderr. This would harm the user
  53. * experience.
  54. */
  55. /**
  56. * virshCommaStringListComplete:
  57. * @input: user input so far
  58. * @options: ALL options available for argument
  59. *
  60. * Some arguments to our commands accept the following form:
  61. *
  62. * virsh command --arg str1,str2,str3
  63. *
  64. * This does not play nicely with our completer funtions, because
  65. * they have to return strings prepended with user's input. For
  66. * instance:
  67. *
  68. * str1,str2,str3,strA
  69. * str1,str2,str3,strB
  70. * str1,str2,str3,strC
  71. *
  72. * This helper function takes care of that. In this specific case
  73. * it would be called as follows:
  74. *
  75. * virshCommaStringListComplete("str1,str2,str3",
  76. * {"strA", "strB", "strC", NULL});
  77. *
  78. * Returns: string list of completions on success,
  79. * NULL otherwise.
  80. */
  81. char **
  82. virshCommaStringListComplete(const char *input,
  83. const char **options)
  84. {
  85. const size_t optionsLen = virStringListLength(options);
  86. g_autofree char *inputCopy = NULL;
  87. VIR_AUTOSTRINGLIST inputList = NULL;
  88. VIR_AUTOSTRINGLIST ret = NULL;
  89. size_t nret = 0;
  90. size_t i;
  91. if (STREQ_NULLABLE(input, " "))
  92. input = NULL;
  93. if (input) {
  94. char *comma = NULL;
  95. inputCopy = g_strdup(input);
  96. if ((comma = strrchr(inputCopy, ',')))
  97. *comma = '\0';
  98. else
  99. VIR_FREE(inputCopy);
  100. }
  101. if (inputCopy && !(inputList = virStringSplit(inputCopy, ",", 0)))
  102. return NULL;
  103. if (VIR_ALLOC_N(ret, optionsLen + 1) < 0)
  104. return NULL;
  105. for (i = 0; i < optionsLen; i++) {
  106. if (virStringListHasString((const char **)inputList, options[i]))
  107. continue;
  108. if (inputCopy)
  109. ret[nret] = g_strdup_printf("%s,%s", inputCopy, options[i]);
  110. else
  111. ret[nret] = g_strdup(options[i]);
  112. nret++;
  113. }
  114. return g_steal_pointer(&ret);
  115. }