@@ -86,6 +86,15 @@ static void cmd_generic(yacli *cli,int cnt,char **cmd) {
8686 yacli_print (cli ,"some line #%d :)\n" ,i );
8787}
8888
89+ static void cmd_mix (yacli * cli ,int cnt ,char * * cmd ) { // exercises mixed literal/regex/dyn siblings
90+ int i ;
91+
92+ yacli_print (cli ,"mix path matched, argc=%d:" ,cnt );
93+ for (i = 0 ;i < cnt ;i ++ )
94+ yacli_print (cli ," [%s]" ,cmd [i ]);
95+ yacli_print (cli ,"\n" );
96+ }
97+
8998static void list_cb (yacli * cli ,void * ctx ,int code ) {
9099 char s [50 ];
91100 int i ,j ;
@@ -194,8 +203,10 @@ int main(void) {
194203 yacli_add_cmd (cli ,ip3 ,"@4" ,"Display IP information" ,cmd_generic );
195204
196205 pip = yacli_add_cmd (cli ,pshow ,"ip" ,"Display IP information" ,cmd_generic );
197- //yacli_add_cmd(cli,pip,"<A.B.C.D|XX:XX::XX:XX>","Display IP information",cmd_generic);
198206 yacli_add_cmd (cli ,pip ,"@1" ,"Display IP information" ,cmd_generic );
207+ // previously rejected by yacli (literal + regex/dyn at same level); now exercised end-to-end
208+ yacli_add_cmd (cli ,pip ,"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)[.]){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" ,"<A.B.C.D>" ,cmd_generic );
209+ yacli_add_cmd (cli ,pip ,"summary" ,"Summary view alongside the regex/dyn siblings" ,cmd_generic );
199210 yacli_add_cmd (cli ,pshow ,"id" ,"Display shaping class information" ,cmd_generic );
200211 yacli_add_cmd (cli ,pshow ,"shaper" ,"Display shaper tree information" ,cmd_generic );
201212 yacli_add_cmd (cli ,pshow ,"map" ,"Display traffic map information" ,cmd_generic );
@@ -237,6 +248,28 @@ int main(void) {
237248
238249 ip1 = yacli_add_cmd (cli ,NULL ,"file" ,"file path test" ,cmd_bliak );
239250 yacli_add_cmd (cli ,ip1 ,"^[^`{<|:,;>}'\"]+$" ,"<file_path>" ,cmd_bliak );
251+
252+ // mixed-siblings probe: two literals + a regex + a dyn list at the same level
253+ // expected behaviour (post-relaxation):
254+ // `mix start` / `mix stop` → literal exact match
255+ // `mix s` <TAB> → ambiguous prefix completion (start vs stop vs summary)
256+ // `mix 1.2.3.4` → falls through literals, hits the IPv4 regex
257+ // `mix eth0` → falls through literals, hits a dyn item
258+ // `?` at `mix ` → lists literals + regex placeholder + dyn list
259+ ip1 = yacli_add_cmd (cli ,NULL ,"mix" ,"Mixed literal/regex/dyn-sibling probe" ,NULL );
260+ yacli_add_cmd (cli ,ip1 ,"start" ,"Mix: start literal" ,cmd_mix );
261+ yacli_add_cmd (cli ,ip1 ,"stop" ,"Mix: stop literal" ,cmd_mix );
262+ yacli_add_cmd (cli ,ip1 ,"summary" ,"Mix: summary literal (shares prefix with stop/start? no — distinct)" ,cmd_mix );
263+ yacli_add_cmd (cli ,ip1 ,"@0" ,"interface name (dyn)" ,cmd_mix );
264+ yacli_add_cmd (cli ,ip1 ,"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)[.]){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" ,"<A.B.C.D>" ,cmd_mix );
265+
266+ // malformed-regex rejection: yacli_add_cmd should refuse this and return NULL
267+ if (yacli_add_cmd (cli ,NULL ,"^bad[regex" ,"<bad-regex>" ,cmd_mix )!= NULL )
268+ fprintf (stderr ,"BUG: malformed regex was accepted\n" );
269+
270+ // small history cap so eviction is easy to observe via Ctrl-X Ctrl-H
271+ yacli_set_hist_max (cli ,5 );
272+
240273 yacli_start (cli );
241274
242275 for (;;) {
0 commit comments