Advertisement
pjakma

Untitled

Nov 27th, 2015
141
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 16.74 KB | None | 0 0
  1. From ebbf6b56fd1f5908d06bf186c543b894ce461743 Mon Sep 17 00:00:00 2001
  2. From: Paul Jakma <paul@quagga.net>
  3. Date: Wed, 19 Aug 2009 13:22:46 +0100
  4. Subject: lib: Do better filtering of arguments, optional args particularly
  5.  
  6. * command.c: (cmd_deopt) helper to extract the inside argument string from
  7.   an optional argument.
  8.  
  9.   (cmd_match) Consolidate matching code from cmd_filter_by_* to here.
  10.   Use cmd_deopt to match on the /inner/ argument of an optional string,
  11.   rather than treating optional arguments as matching pretty much any
  12.   string.
  13.  
  14.   (cmd_filter) consolidate cmd_filter_by_* to here, and use cmd_match.
  15.   Further, do a two-pass filter, to make use of the fact that we know
  16.   the "strongest" match (e.g. range-match args beat variables) and can
  17.   filter out weaker ones.
  18.  
  19.   Along with ability to match on inside of optional arguments, this makes
  20.   our command definitions more powerful, and should allow us to avoid
  21.   much redundancy in command defs.
  22.  
  23.   (is_cmd_ambiguous) look inside optional args, for better matching.
  24.  
  25. diff --git a/lib/command.c b/lib/command.c
  26. index 31c067a..c3ea5c2 100644
  27. --- a/lib/command.c
  28. +++ b/lib/command.c
  29. @@ -32,6 +32,7 @@ Boston, MA 02111-1307, USA.  */
  30.  #include "vty.h"
  31.  #include "command.h"
  32.  #include "workqueue.h"
  33. +#include <stdbool.h>
  34.  
  35.  /* Command vector which includes some level of command lists. Normally
  36.     each daemon maintains each own cmdvec. */
  37. @@ -686,7 +687,8 @@ cmd_filter_by_symbol (char *command, char *symbol)
  38.  /* Completion match types. */
  39.  enum match_type
  40.  {
  41. -  no_match,
  42. +  no_match = 0,
  43. +  any_match,
  44.    extend_match,
  45.    ipv4_prefix_match,
  46.    ipv4_match,
  47. @@ -695,7 +697,7 @@ enum match_type
  48.    range_match,
  49.    vararg_match,
  50.    partly_match,
  51. -  exact_match
  52. +  exact_match,
  53.  };
  54.  
  55.  static enum match_type
  56. @@ -1132,12 +1134,100 @@ cmd_range_match (const char *range, const char *str)
  57.    return 1;
  58.  }
  59.  
  60. -/* Make completion match and return match type flag. */
  61. +/* helper to retrieve the 'real' argument string from an optional argument */
  62. +static char *
  63. +cmd_deopt (const char *str)
  64. +{
  65. +  /* we've got "[blah]". We want to strip off the []s and redo the
  66. +   * match check for "blah"
  67. +   */
  68. +  size_t len = strlen (str);
  69. +  char *tmp;
  70. +  
  71. +  if (len < 3)
  72. +    return NULL;
  73. +  
  74. +  /* tmp will hold a string of len-2 chars, so 'len' size is fine */
  75. +  tmp = XMALLOC(MTYPE_TMP, len);
  76. +
  77. +  memcpy (tmp, (str + 1), len - 2);
  78. +  tmp[len - 2] = '\0';
  79. +  
  80. +  return tmp;
  81. +}
  82. +
  83.  static enum match_type
  84. -cmd_filter_by_completion (char *command, vector v, unsigned int index)
  85. +cmd_match (const char *str, const char *command,
  86. +           enum match_type min, bool recur)
  87. +{
  88. +  
  89. +  if (recur && CMD_OPTION(str))
  90. +    {
  91. +      enum match_type ret;
  92. +      char *tmp = cmd_deopt (str);
  93. +      
  94. +      /* this would be a bug in a command, however handle it gracefully
  95. +       * as it we only discover it if a user tries to run it
  96. +       */
  97. +      if (tmp == NULL)
  98. +        return no_match;
  99. +      
  100. +      ret = cmd_match (tmp, command, min, false);
  101. +      
  102. +      XFREE (MTYPE_TMP, tmp);
  103. +      
  104. +      return ret;
  105. +    }
  106. +  else if (CMD_VARARG (str))
  107. +    return vararg_match;
  108. +  else if (CMD_RANGE (str))
  109. +    {
  110. +      if (cmd_range_match (str, command))
  111. +        return range_match;
  112. +    }
  113. +#ifdef HAVE_IPV6
  114. +  else if (CMD_IPV6 (str))
  115. +    {
  116. +      if (cmd_ipv6_match (command) >= min)
  117. +        return ipv6_match;
  118. +    }
  119. +  else if (CMD_IPV6_PREFIX (str))
  120. +    {
  121. +      if (cmd_ipv6_prefix_match (command) >= min)
  122. +        return ipv6_prefix_match;
  123. +    }
  124. +#endif /* HAVE_IPV6  */
  125. +  else if (CMD_IPV4 (str))
  126. +    {
  127. +      if (cmd_ipv4_match (command) >= min)
  128. +        return ipv4_match;
  129. +    }
  130. +  else if (CMD_IPV4_PREFIX (str))
  131. +    {
  132. +      if (cmd_ipv4_prefix_match (command) >= min)
  133. +        return ipv4_prefix_match;
  134. +    }
  135. +  else if (CMD_VARIABLE (str))
  136. +    return extend_match;
  137. +  else if (strncmp (command, str, strlen (command)) == 0)
  138. +    {
  139. +      if (strcmp (command, str) == 0)
  140. +        return  exact_match;
  141. +      else if (partly_match >= min)
  142. +        return partly_match;
  143. +    }
  144. +  
  145. +  return no_match;
  146. +}
  147. +
  148. +/* Filter vector at the specified index and by the given command string, to
  149. + * the desired matching level (thus allowing part matches), and return match
  150. + * type flag.
  151. + */
  152. +static enum match_type
  153. +cmd_filter (char *command, vector v, unsigned int index, enum match_type level)
  154.  {
  155.    unsigned int i;
  156. -  const char *str;
  157.    struct cmd_element *cmd_element;
  158.    enum match_type match_type;
  159.    vector descvec;
  160. @@ -1160,112 +1250,42 @@ cmd_filter_by_completion (char *command, vector v, unsigned int index)
  161.  
  162.             for (j = 0; j < vector_active (descvec); j++)
  163.               if ((desc = vector_slot (descvec, j)))
  164. -               {
  165. -                 str = desc->cmd;
  166. +               {
  167. +                 enum match_type ret;
  168. +                
  169. +                 ret = cmd_match (desc->cmd, command, level, true);
  170.                  
  171. -                 if (CMD_VARARG (str))
  172. -                   {
  173. -                     if (match_type < vararg_match)
  174. -                       match_type = vararg_match;
  175. -                     matched++;
  176. -                   }
  177. -                 else if (CMD_RANGE (str))
  178. -                   {
  179. -                     if (cmd_range_match (str, command))
  180. -                       {
  181. -                         if (match_type < range_match)
  182. -                           match_type = range_match;
  183. -
  184. -                         matched++;
  185. -                       }
  186. -                   }
  187. -#ifdef HAVE_IPV6
  188. -                 else if (CMD_IPV6 (str))
  189. -                   {
  190. -                     if (cmd_ipv6_match (command))
  191. -                       {
  192. -                         if (match_type < ipv6_match)
  193. -                           match_type = ipv6_match;
  194. -
  195. -                         matched++;
  196. -                       }
  197. -                   }
  198. -                 else if (CMD_IPV6_PREFIX (str))
  199. -                   {
  200. -                     if (cmd_ipv6_prefix_match (command))
  201. -                       {
  202. -                         if (match_type < ipv6_prefix_match)
  203. -                           match_type = ipv6_prefix_match;
  204. -
  205. -                         matched++;
  206. -                       }
  207. -                   }
  208. -#endif /* HAVE_IPV6  */
  209. -                 else if (CMD_IPV4 (str))
  210. -                   {
  211. -                     if (cmd_ipv4_match (command))
  212. -                       {
  213. -                         if (match_type < ipv4_match)
  214. -                           match_type = ipv4_match;
  215. -
  216. -                         matched++;
  217. -                       }
  218. -                   }
  219. -                 else if (CMD_IPV4_PREFIX (str))
  220. -                   {
  221. -                     if (cmd_ipv4_prefix_match (command))
  222. -                       {
  223. -                         if (match_type < ipv4_prefix_match)
  224. -                           match_type = ipv4_prefix_match;
  225. -                         matched++;
  226. -                       }
  227. -                   }
  228. -                 else
  229. -                   /* Check is this point's argument optional ? */
  230. -                 if (CMD_OPTION (str) || CMD_VARIABLE (str))
  231. -                   {
  232. -                     if (match_type < extend_match)
  233. -                       match_type = extend_match;
  234. -                     matched++;
  235. -                   }
  236. -                 else if (strncmp (command, str, strlen (command)) == 0)
  237. -                   {
  238. -                     if (strcmp (command, str) == 0)
  239. -                       match_type = exact_match;
  240. -                     else
  241. -                       {
  242. -                         if (match_type < partly_match)
  243. -                           match_type = partly_match;
  244. -                       }
  245. -                     matched++;
  246. -                   }
  247. +                 if (ret != no_match)
  248. +                   matched++;
  249. +                  
  250. +                 if (match_type < ret)
  251. +                   match_type = ret;
  252.                 }
  253.             if (!matched)
  254.               vector_slot (v, i) = NULL;
  255.           }
  256.        }
  257. -  return match_type;
  258. -}
  259. -
  260. -/* Filter vector by command character with index. */
  261. -static enum match_type
  262. -cmd_filter_by_string (char *command, vector v, unsigned int index)
  263. -{
  264. -  unsigned int i;
  265. -  const char *str;
  266. -  struct cmd_element *cmd_element;
  267. -  enum match_type match_type;
  268. -  vector descvec;
  269. -  struct desc *desc;
  270. -
  271. -  match_type = no_match;
  272. -
  273. -  /* If command and cmd_element string does not match set NULL to vector */
  274. +  
  275. +  if (match_type == no_match)
  276. +    return no_match;
  277. +  
  278. +  /* 2nd pass: We now know the 'strongest' match type for the index, so we
  279. +   * go again and filter out commands whose argument (at this index) is
  280. +   * 'weaker'. E.g., if we have 2 commands:
  281. +   *
  282. +   *   foo bar <1-255>
  283. +   *   foo bar BLAH
  284. +   *
  285. +   * and the command string is 'foo bar 10', then we will get here with with
  286. +   * 'range_match' being the strongest match.  However, if 'BLAH' came
  287. +   * earlier, it won't have been filtered out (as a CMD_VARIABLE allows "10").
  288. +   *
  289. +   * If we don't do a 2nd pass and filter it out, the higher-layers will
  290. +   * consider this to be ambiguous.
  291. +   */
  292.    for (i = 0; i < vector_active (v); i++)
  293.      if ((cmd_element = vector_slot (v, i)) != NULL)
  294.        {
  295. -       /* If given index is bigger than max string vector of command,
  296. -          set NULL */
  297.         if (index >= vector_active (cmd_element->strvec))
  298.           vector_slot (v, i) = NULL;
  299.         else
  300. @@ -1277,81 +1297,19 @@ cmd_filter_by_string (char *command, vector v, unsigned int index)
  301.  
  302.             for (j = 0; j < vector_active (descvec); j++)
  303.               if ((desc = vector_slot (descvec, j)))
  304. -               {
  305. -                 str = desc->cmd;
  306. -
  307. -                 if (CMD_VARARG (str))
  308. -                   {
  309. -                     if (match_type < vararg_match)
  310. -                       match_type = vararg_match;
  311. -                     matched++;
  312. -                   }
  313. -                 else if (CMD_RANGE (str))
  314. -                   {
  315. -                     if (cmd_range_match (str, command))
  316. -                       {
  317. -                         if (match_type < range_match)
  318. -                           match_type = range_match;
  319. -                         matched++;
  320. -                       }
  321. -                   }
  322. -#ifdef HAVE_IPV6
  323. -                 else if (CMD_IPV6 (str))
  324. -                   {
  325. -                     if (cmd_ipv6_match (command) == exact_match)
  326. -                       {
  327. -                         if (match_type < ipv6_match)
  328. -                           match_type = ipv6_match;
  329. -                         matched++;
  330. -                       }
  331. -                   }
  332. -                 else if (CMD_IPV6_PREFIX (str))
  333. -                   {
  334. -                     if (cmd_ipv6_prefix_match (command) == exact_match)
  335. -                       {
  336. -                         if (match_type < ipv6_prefix_match)
  337. -                           match_type = ipv6_prefix_match;
  338. -                         matched++;
  339. -                       }
  340. -                   }
  341. -#endif /* HAVE_IPV6  */
  342. -                 else if (CMD_IPV4 (str))
  343. -                   {
  344. -                     if (cmd_ipv4_match (command) == exact_match)
  345. -                       {
  346. -                         if (match_type < ipv4_match)
  347. -                           match_type = ipv4_match;
  348. -                         matched++;
  349. -                       }
  350. -                   }
  351. -                 else if (CMD_IPV4_PREFIX (str))
  352. -                   {
  353. -                     if (cmd_ipv4_prefix_match (command) == exact_match)
  354. -                       {
  355. -                         if (match_type < ipv4_prefix_match)
  356. -                           match_type = ipv4_prefix_match;
  357. -                         matched++;
  358. -                       }
  359. -                   }
  360. -                 else if (CMD_OPTION (str) || CMD_VARIABLE (str))
  361. -                   {
  362. -                     if (match_type < extend_match)
  363. -                       match_type = extend_match;
  364. -                     matched++;
  365. -                   }
  366. -                 else
  367. -                   {
  368. -                     if (strcmp (command, str) == 0)
  369. -                       {
  370. -                         match_type = exact_match;
  371. -                         matched++;
  372. -                       }
  373. -                   }
  374. +               {
  375. +                 enum match_type ret;
  376. +                
  377. +                 ret = cmd_match (desc->cmd, command, any_match, true);
  378. +                
  379. +                 if (ret >= match_type)
  380. +                   matched++;
  381.                 }
  382.             if (!matched)
  383.               vector_slot (v, i) = NULL;
  384.           }
  385.        }
  386. +
  387.    return match_type;
  388.  }
  389.  
  390. @@ -1361,7 +1319,6 @@ is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
  391.  {
  392.    unsigned int i;
  393.    unsigned int j;
  394. -  const char *str = NULL;
  395.    struct cmd_element *cmd_element;
  396.    const char *matched = NULL;
  397.    vector descvec;
  398. @@ -1371,25 +1328,28 @@ is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
  399.      if ((cmd_element = vector_slot (v, i)) != NULL)
  400.        {
  401.         int match = 0;
  402. -
  403. +
  404.         descvec = vector_slot (cmd_element->strvec, index);
  405.  
  406.         for (j = 0; j < vector_active (descvec); j++)
  407.           if ((desc = vector_slot (descvec, j)))
  408.             {
  409.               enum match_type ret;
  410. +             char *str = desc->cmd;
  411. +            
  412. +             if (CMD_OPTION(str))
  413. +               if ((str = cmd_deopt (str)) == NULL)
  414. +                 continue;
  415.              
  416. -             str = desc->cmd;
  417. -
  418.               switch (type)
  419.                 {
  420.                 case exact_match:
  421. -                 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
  422. +                 if (!(CMD_VARIABLE (str))
  423.                       && strcmp (command, str) == 0)
  424.                     match++;
  425.                   break;
  426.                 case partly_match:
  427. -                 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
  428. +                 if (!(CMD_VARIABLE (str))
  429.                       && strncmp (command, str, strlen (command)) == 0)
  430.                     {
  431.                       if (matched && strcmp (matched, str) != 0)
  432. @@ -1438,13 +1398,16 @@ is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
  433.                     }
  434.                   break;
  435.                 case extend_match:
  436. -                 if (CMD_OPTION (str) || CMD_VARIABLE (str))
  437. +                 if (CMD_VARIABLE (str))
  438.                     match++;
  439.                   break;
  440.                 case no_match:
  441.                 default:
  442.                   break;
  443.                 }
  444. +              
  445. +              if (CMD_OPTION(desc->cmd))
  446. +                XFREE (MTYPE_TMP, str);
  447.             }
  448.         if (!match)
  449.           vector_slot (v, i) = NULL;
  450. @@ -1614,7 +1577,7 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status)
  451.    for (i = 0; i < index; i++)
  452.      if ((command = vector_slot (vline, i)))
  453.        {
  454. -       match = cmd_filter_by_completion (command, cmd_vector, i);
  455. +       match = cmd_filter (command, cmd_vector, i, any_match);
  456.  
  457.         if (match == vararg_match)
  458.           {
  459. @@ -1663,7 +1626,7 @@ cmd_describe_command_real (vector vline, struct vty *vty, int *status)
  460.    /* Make sure that cmd_vector is filtered based on current word */
  461.    command = vector_slot (vline, index);
  462.    if (command)
  463. -    match = cmd_filter_by_completion (command, cmd_vector, index);
  464. +    match = cmd_filter (command, cmd_vector, index, any_match);
  465.  
  466.    /* Make description vector. */
  467.    for (i = 0; i < vector_active (cmd_vector); i++)
  468. @@ -1817,7 +1780,7 @@ cmd_complete_command_real (vector vline, struct vty *vty, int *status)
  469.         int ret;
  470.  
  471.         /* First try completion match, if there is exactly match return 1 */
  472. -       match = cmd_filter_by_completion (command, cmd_vector, i);
  473. +       match = cmd_filter (command, cmd_vector, i, any_match);
  474.  
  475.         /* If there is exact match then filter ambiguous match else check
  476.            ambiguousness. */
  477. @@ -2026,7 +1989,7 @@ cmd_execute_command_real (vector vline, struct vty *vty,
  478.        {
  479.         int ret;
  480.  
  481. -       match = cmd_filter_by_completion (command, cmd_vector, index);
  482. +       match = cmd_filter (command, cmd_vector, index, any_match);
  483.  
  484.         if (match == vararg_match)
  485.           break;
  486. @@ -2205,8 +2168,8 @@ cmd_execute_command_strict (vector vline, struct vty *vty,
  487.        {
  488.         int ret;
  489.  
  490. -       match = cmd_filter_by_string (vector_slot (vline, index),
  491. -                                     cmd_vector, index);
  492. +       match = cmd_filter (vector_slot (vline, index), cmd_vector,
  493. +                           index, exact_match);
  494.  
  495.         /* If command meets '.VARARG' then finish matching. */
  496.         if (match == vararg_match)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement