Browse code

sercmd: tab completion support for mi commands

- tab completion is now supported for mi commands.
E.g.:
sercmd> mi p<TAB><TAB>
ps pwd
sercmd> mi pw<TAB>
sercmd> mi pwd

Andrei Pelinescu-Onciul authored on 29/06/2009 09:03:46
Showing 1 changed files
... ...
@@ -31,6 +31,7 @@
31 31
  * --------
32 32
  *  2006-02-14  created by andrei
33 33
  *  2009-06-29  command line completion for cfg groups and vars (andrei)
34
+ *  2009-06-30  command line completion for mi cmds (andrei)
34 35
  */
35 36
 
36 37
 
... ...
@@ -51,7 +52,8 @@
51 51
 #include <readline/readline.h>
52 52
 #include <readline/history.h>
53 53
 
54
-#define USE_CFG_VARS
54
+#define USE_CFG_VARS /* cfg group and vars completion */
55
+#define USE_MI  /* mi completion */
55 56
 #endif
56 57
 
57 58
 #include "parse_listen_id.h"
... ...
@@ -127,7 +129,6 @@ int rpc_no=0;
127 127
 
128 128
 #ifdef USE_CFG_VARS
129 129
 
130
-
131 130
 struct binrpc_val* cfg_vars_array;
132 131
 int cfg_vars_no;
133 132
 
... ...
@@ -142,6 +143,13 @@ struct cfg_var_grp* cfg_grp_lst; /** cfg groups list, allong with var names*/
142 142
 struct cfg_var_grp* crt_cfg_grp;
143 143
 #endif /* USE_CFG_VARS */
144 144
 
145
+#ifdef USE_MI
146
+struct binrpc_val* mi_which_array;
147
+int mi_which_no;
148
+
149
+str* mi_cmds;
150
+int mi_cmds_no;
151
+#endif /* USE_MI */
145 152
 
146 153
 
147 154
 
... ...
@@ -262,12 +270,16 @@ static struct sercmd_builtin builtins[]={
262 262
 #ifdef USE_READLINE
263 263
 
264 264
 enum complete_states {
265
-	COMPLETE_NOTHING,
265
+	COMPLETE_INIT,
266 266
 	COMPLETE_CMD_NAME,
267 267
 #ifdef USE_CFG_VARS
268 268
 	COMPLETE_CFG_GRP,
269
-	COMPLETE_CFG_VAR
269
+	COMPLETE_CFG_VAR,
270 270
 #endif /* USE_CFG_VARS */
271
+#ifdef USE_MI
272
+	COMPLETE_MI,
273
+#endif /* USE_Mi */
274
+	COMPLETE_NOTHING
271 275
 };
272 276
 
273 277
 /* instead of rl_attempted_completion_over which is not present in
... ...
@@ -298,6 +310,14 @@ char* complete_params_cfg_var[]={
298 298
 };
299 299
 #endif /* USE_CFG_VARS */
300 300
 
301
+#ifdef USE_MI
302
+/* commands for which we complete the first param with an mi command*/
303
+char* complete_params_mi[]={
304
+	"mi",
305
+	0
306
+};
307
+#endif /* USE_MI */
308
+
301 309
 #endif /* USE_READLINE */
302 310
 
303 311
 
... ...
@@ -1155,7 +1175,7 @@ static int get_sercmd_list(int s)
1155 1155
 			}
1156 1156
 			break;
1157 1157
 		case BINRPC_REPL:
1158
-			rpc_no=10; /* default cmd list */
1158
+			rpc_no=100; /* default cmd list */
1159 1159
 			if ((rpc_array=parse_reply_body(&rpc_no, &in_pkt, msg_body,
1160 1160
 												in_pkt.tlen))==0)
1161 1161
 				goto error;
... ...
@@ -1173,6 +1193,30 @@ error:
1173 1173
 
1174 1174
 
1175 1175
 
1176
+#if defined(USE_CFG_VARS) || defined (USE_MI)
1177
+/** check if cmd is a rpc command.
1178
+ * Quick check (using the internal rpc_array) if cmd is a valid rpc command.
1179
+ * @param cmd - null terminated ascii string
1180
+ * @return 1 on success, 0 on failure.
1181
+ */
1182
+static int is_rpc_cmd(char* cmd)
1183
+{
1184
+	int r;
1185
+	int cmd_len;
1186
+	
1187
+	cmd_len=strlen(cmd);
1188
+	for (r=0; r<rpc_no; r++){
1189
+		if ((rpc_array[r].type==BINRPC_T_STR) &&
1190
+			(rpc_array[r].u.strval.len==cmd_len) &&
1191
+			(strncmp(cmd, rpc_array[r].u.strval.s, cmd_len)==0))
1192
+			return 1;
1193
+	}
1194
+	return 0;
1195
+}
1196
+#endif /* USE_CFG_VARS || USE_MI */
1197
+
1198
+
1199
+
1176 1200
 #ifdef USE_CFG_VARS
1177 1201
 /* retrieve the cfg vars and group list */
1178 1202
 static int get_cfgvars_list(int s)
... ...
@@ -1193,6 +1237,7 @@ static int get_cfgvars_list(int s)
1193 1193
 	
1194 1194
 	cmd.method="cfg.list";
1195 1195
 	cmd.argc=0;
1196
+	if (!is_rpc_cmd(cmd.method)) goto error;
1196 1197
 	
1197 1198
 	cookie=gen_cookie();
1198 1199
 	if ((ret=send_binrpc_cmd(s, &cmd, cookie))<0){
... ...
@@ -1321,6 +1366,132 @@ void free_cfg_grp_lst()
1321 1321
 
1322 1322
 
1323 1323
 
1324
+#ifdef USE_MI
1325
+/* retrieve the mi list */
1326
+static int get_mi_list(int s)
1327
+{
1328
+	struct binrpc_cmd cmd;
1329
+	int cookie;
1330
+	unsigned char reply_buf[MAX_REPLY_SIZE];
1331
+	unsigned char* msg_body;
1332
+	struct binrpc_parse_ctx in_pkt;
1333
+	char* p;
1334
+	char* end;
1335
+	str mi_name;
1336
+	int mi_which_results;
1337
+	int r;
1338
+	int ret;
1339
+	
1340
+	cmd.method="mi";
1341
+	cmd.argv[0].type=BINRPC_T_STR;
1342
+	cmd.argv[0].u.strval.s="which";
1343
+	cmd.argv[0].u.strval.len=strlen(cmd.argv[0].u.strval.s);
1344
+	cmd.argc=1;
1345
+	if (!is_rpc_cmd(cmd.method)) goto error;
1346
+	
1347
+	cookie=gen_cookie();
1348
+	if ((ret=send_binrpc_cmd(s, &cmd, cookie))<0){
1349
+		if (ret==-1) goto error_send;
1350
+		else goto binrpc_err;
1351
+	}
1352
+	/* read reply */
1353
+	memset(&in_pkt, 0, sizeof(in_pkt));
1354
+	if ((ret=get_reply(s, reply_buf, MAX_REPLY_SIZE, cookie, &in_pkt,
1355
+					&msg_body))<0){
1356
+		goto error;
1357
+	}
1358
+	switch(in_pkt.type){
1359
+		case BINRPC_FAULT:
1360
+			if (print_fault(&in_pkt, msg_body, in_pkt.tlen)<0){
1361
+				goto error;
1362
+			}
1363
+			break;
1364
+		case BINRPC_REPL:
1365
+			mi_which_no=25; /* default rpc list */
1366
+			if ((mi_which_array=parse_reply_body(&mi_which_no, &in_pkt,
1367
+												msg_body, in_pkt.tlen))==0)
1368
+				goto error;
1369
+			break;
1370
+		default:
1371
+			fprintf(stderr, "ERROR: not a reply\n");
1372
+			goto error;
1373
+	}
1374
+	
1375
+	
1376
+	/* get the mi commands number */
1377
+	mi_which_results=0;
1378
+	for (r=0; r<mi_which_no; r++){
1379
+		if (mi_which_array[r].type!=BINRPC_T_STR)
1380
+			continue;
1381
+		/* we are interestend only in lines starting with '+', e.g.:
1382
+		   + :: version */
1383
+		if ((mi_which_array[r].u.strval.len) &&
1384
+			(mi_which_array[r].u.strval.s[0]=='+'))
1385
+			mi_which_results++;
1386
+	}
1387
+	/* no mi commands */
1388
+	if (mi_which_results==0)
1389
+		goto error;
1390
+	/* alloc the mi_cmds array */
1391
+	mi_cmds=malloc(mi_which_results*sizeof(*mi_cmds));
1392
+	if (mi_cmds==0) goto error_mem;
1393
+	memset(mi_cmds, 0, mi_which_results* sizeof(mi_cmds));
1394
+	/* get the mi names list */
1395
+	for (r=0; r<mi_which_no; r++){
1396
+		if (mi_which_array[r].type!=BINRPC_T_STR)
1397
+			continue;
1398
+		p=mi_which_array[r].u.strval.s;
1399
+		end=p+mi_which_array[r].u.strval.len;
1400
+		/* we are interestend only in lines starting with '+', e.g.:
1401
+		   + :: version */
1402
+		if ((p>=end) || (*p!='+'))
1403
+			continue;
1404
+		p++;
1405
+		/* skip over to the first ':' */
1406
+		for(;p<end && *p!=':'; p++);
1407
+		if (p>=end) continue;
1408
+		p++;
1409
+		/* skip over to the next ':' */
1410
+		for(;p<end && *p!=':'; p++);
1411
+		if (p>=end) continue;
1412
+		p++;
1413
+		/* skip over spaces */
1414
+		for(;p<end && (*p==' ' || *p=='\t'); p++);
1415
+		if (p>=end) continue;
1416
+		if (mi_cmds_no >= mi_which_results){
1417
+			fprintf(stderr, "BUG: wrong mi cmds no (%d >= %d)\n",
1418
+							mi_cmds_no, mi_which_results);
1419
+			goto error;
1420
+		}
1421
+		mi_name.s=p;
1422
+		mi_name.len=(int)(long)(end-p);
1423
+		mi_cmds[mi_cmds_no]=mi_name;
1424
+		mi_cmds_no++;
1425
+	}
1426
+	
1427
+	return 0;
1428
+binrpc_err:
1429
+error_send:
1430
+error:
1431
+error_mem:
1432
+	return -1;
1433
+}
1434
+
1435
+
1436
+
1437
+void free_mi_cmds()
1438
+{
1439
+	if (mi_cmds){
1440
+		free(mi_cmds);
1441
+		mi_cmds=0;
1442
+		mi_cmds_no=0;
1443
+	}
1444
+}
1445
+#endif /* USE_MI */
1446
+
1447
+
1448
+
1449
+
1324 1450
 static void print_formatting(char* prefix, char* format, char* suffix)
1325 1451
 {
1326 1452
 	if (format){
... ...
@@ -1441,6 +1612,7 @@ static char* sercmd_generator(const char* text, int state)
1441 1441
 	static struct cfg_var_grp* grp;
1442 1442
 #endif
1443 1443
 	switch(attempted_completion_state){
1444
+		case COMPLETE_INIT:
1444 1445
 		case COMPLETE_NOTHING:
1445 1446
 			return 0;
1446 1447
 		case COMPLETE_CMD_NAME:
... ...
@@ -1527,6 +1699,29 @@ static char* sercmd_generator(const char* text, int state)
1527 1527
 			}
1528 1528
 			break;
1529 1529
 #endif /* USE_CFG_VARS */
1530
+#ifdef USE_MI
1531
+		case COMPLETE_MI:
1532
+			if (state==0){
1533
+				/* init */
1534
+				len=strlen(text);
1535
+				idx=0;
1536
+			}
1537
+			while(idx < mi_cmds_no){
1538
+				if (len<=mi_cmds[idx].len &&
1539
+						memcmp(text, mi_cmds[idx].s, len)==0) {
1540
+					/* zero-term copy of the var name */
1541
+					name=malloc(mi_cmds[idx].len+1);
1542
+					if (name){
1543
+						memcpy(name, mi_cmds[idx].s, mi_cmds[idx].len);
1544
+						name[mi_cmds[idx].len]=0;
1545
+					}
1546
+					idx++;
1547
+					return name;
1548
+				}
1549
+				idx++;
1550
+			}
1551
+			break;
1552
+#endif /* USE_MI */
1530 1553
 	}
1531 1554
 	/* no matches */
1532 1555
 	return 0;
... ...
@@ -1594,6 +1789,20 @@ char** sercmd_completion(const char* text, int start, int end)
1594 1594
 						goto end;
1595 1595
 				}
1596 1596
 			}
1597
+#endif /* USE_CFG_VARS */
1598
+#ifdef USE_MI
1599
+			/* try complete_parms_mi */
1600
+			for(i=0; complete_params_mi[i]; i++){
1601
+				if ((cmd_len==strlen(complete_params_mi[i])) &&
1602
+						(strncmp(&rl_line_buffer[cmd_start],
1603
+								 complete_params_mi[i],
1604
+								 cmd_len)==0)){
1605
+						attempted_completion_state=COMPLETE_MI;
1606
+						goto end;
1607
+				}
1608
+			}
1609
+#endif /* USE_MI */
1610
+#ifdef USE_CFG_VARS
1597 1611
 		}else if (crt_param_no==2){
1598 1612
 			if (attempted_completion_state!=COMPLETE_CFG_GRP){
1599 1613
 				for(i=0; complete_params_cfg_var[i]; i++){
... ...
@@ -1789,10 +1998,14 @@ int main(int argc, char** argv)
1789 1789
 		goto end;
1790 1790
 	}
1791 1791
 	/* interactive mode */
1792
-	get_sercmd_list(s);
1793
-#ifdef USE_CFG_VARS
1794
-	get_cfgvars_list(s);
1795
-#endif /* USE_CFG_VARS */
1792
+	if (get_sercmd_list(s)==0){
1793
+	#ifdef USE_CFG_VARS
1794
+		get_cfgvars_list(s);
1795
+	#endif /* USE_CFG_VARS */
1796
+	#ifdef USE_MI
1797
+		get_mi_list(s);
1798
+	#endif /* USE_MI */
1799
+	}
1796 1800
 	/* banners */
1797 1801
 	printf("%s %s\n", NAME, VERSION);
1798 1802
 	printf("%s\n", COPYRIGHT);
... ...
@@ -1845,9 +2058,21 @@ end:
1845 1845
 #ifdef USE_CFG_VARS
1846 1846
 	if (cfg_grp_lst)
1847 1847
 		free_cfg_grp_lst();
1848
-	if (cfg_vars_array)
1848
+	if (cfg_vars_array){
1849 1849
 		free_rpc_array(cfg_vars_array, cfg_vars_no);
1850
+		cfg_vars_array=0;
1851
+		cfg_vars_no=0;
1852
+	}
1850 1853
 #endif /* USE_CFG_VARS */
1854
+#ifdef USE_MI
1855
+	if (mi_cmds)
1856
+		free_mi_cmds();
1857
+	if (mi_which_array){
1858
+		free_rpc_array(mi_which_array, mi_which_no);
1859
+		mi_which_array=0;
1860
+		mi_which_no=0;
1861
+	}
1862
+#endif /* USE_MI */
1851 1863
 	cleanup();
1852 1864
 	exit(0);
1853 1865
 error:
... ...
@@ -1860,9 +2085,21 @@ error:
1860 1860
 #ifdef USE_CFG_VARS
1861 1861
 	if (cfg_grp_lst)
1862 1862
 		free_cfg_grp_lst();
1863
-	if (cfg_vars_array)
1863
+	if (cfg_vars_array){
1864 1864
 		free_rpc_array(cfg_vars_array, cfg_vars_no);
1865
+		cfg_vars_array=0;
1866
+		cfg_vars_no=0;
1867
+	}
1865 1868
 #endif /* USE_CFG_VARS */
1869
+#ifdef USE_MI
1870
+	if (mi_cmds)
1871
+		free_mi_cmds();
1872
+	if (mi_which_array){
1873
+		free_rpc_array(mi_which_array, mi_which_no);
1874
+		mi_which_array=0;
1875
+		mi_which_no=0;
1876
+	}
1877
+#endif /* USE_MI */
1866 1878
 	cleanup();
1867 1879
 	exit(-1);
1868 1880
 }