1 5184 ek110237 /* 2 5184 ek110237 * CDDL HEADER START 3 5184 ek110237 * 4 5184 ek110237 * The contents of this file are subject to the terms of the 5 5184 ek110237 * Common Development and Distribution License (the "License"). 6 5184 ek110237 * You may not use this file except in compliance with the License. 7 5184 ek110237 * 8 5184 ek110237 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 5184 ek110237 * or http://www.opensolaris.org/os/licensing. 10 5184 ek110237 * See the License for the specific language governing permissions 11 5184 ek110237 * and limitations under the License. 12 5184 ek110237 * 13 5184 ek110237 * When distributing Covered Code, include this CDDL HEADER in each 14 5184 ek110237 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 5184 ek110237 * If applicable, add the following below this CDDL HEADER, with the 16 5184 ek110237 * fields enclosed by brackets "[]" replaced with your own identifying 17 5184 ek110237 * information: Portions Copyright [yyyy] [name of copyright owner] 18 5184 ek110237 * 19 5184 ek110237 * CDDL HEADER END 20 5184 ek110237 */ 21 5184 ek110237 /* 22 6391 aw148015 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 5184 ek110237 * Use is subject to license terms. 24 5184 ek110237 */ 25 5184 ek110237 26 5184 ek110237 #pragma ident "%Z%%M% %I% %E% SMI" 27 5184 ek110237 28 5184 ek110237 #include <sys/types.h> 29 5184 ek110237 #include <dirent.h> 30 5184 ek110237 #include <strings.h> 31 6613 ek110237 32 5184 ek110237 #include "filebench.h" 33 5184 ek110237 #include "auto_comp.h" 34 5184 ek110237 35 5184 ek110237 #define VARNAME_MAXLEN 128 36 5184 ek110237 #define FILENAME_MAXLEN 128 37 5184 ek110237 #define MALLOC_STEP 64 38 5184 ek110237 39 5184 ek110237 #define CSUF_CMD " " 40 5184 ek110237 #define CSUF_ARG " " 41 5184 ek110237 #define CSUF_LVARNAME "=" 42 5184 ek110237 #define CSUF_RVARNAME "," 43 5184 ek110237 #define CSUF_ATTRNAME "=" 44 5184 ek110237 45 5184 ek110237 #define ATTR_LIST_SEP ',' 46 5184 ek110237 #define ATTR_ASSIGN_OP '=' 47 5184 ek110237 #define VAR_ASSIGN_OP '=' 48 5184 ek110237 #define VAR_PREFIX '$' 49 5184 ek110237 50 5184 ek110237 typedef char ac_fname_t[FILENAME_MAXLEN]; 51 5184 ek110237 52 5184 ek110237 typedef struct ac_fname_cache { 53 5184 ek110237 ac_fname_t *fnc_buf; 54 5184 ek110237 int fnc_bufsize; 55 5184 ek110237 time_t fnc_mtime; 56 5184 ek110237 } ac_fname_cache_t; 57 5184 ek110237 58 5184 ek110237 typedef enum ac_match_result { 59 5184 ek110237 MATCH_DONE, 60 5184 ek110237 MATCH_CONT 61 5184 ek110237 } ac_match_result_t; 62 5184 ek110237 63 5184 ek110237 /* 64 5184 ek110237 * We parse an user input line into multiple blank separated strings. 65 5184 ek110237 * The last string is always the one user wants to complete, the other 66 5184 ek110237 * preceding strings set up the context on how to complete the last one. 67 5184 ek110237 * 68 5184 ek110237 * ac_str_t repsents one such a string, which can be of the following 69 5184 ek110237 * types: 70 5184 ek110237 * 71 5184 ek110237 * STRTYPE_COMPLETE - the string is one of the preceding strings. 72 5184 ek110237 * STRTYPE_INCOMPLETE - the string is the one being completed, user 73 5184 ek110237 * has inputted at least one character for it. 74 5184 ek110237 * STRTYPE_NULL - the string is the one being completed, user 75 5184 ek110237 * has inputted nothing for it. 76 5184 ek110237 * 77 5184 ek110237 * ac_str_t structure has the following members: 78 5184 ek110237 * 79 5184 ek110237 * startp - the start position of the string in the user input buffer 80 5184 ek110237 * endp - the end position of the string in the user input buffer 81 5184 ek110237 * strtype - the type of the string. It can be of the following values: 82 5184 ek110237 * STRTYPE_COMPLETE, STRTYPE_INCOMPLETE, STRTYPE_NULL, 83 5184 ek110237 * and STRTYPE_INVALID. 84 5184 ek110237 */ 85 5184 ek110237 86 5184 ek110237 typedef enum ac_strtype { 87 5184 ek110237 STRTYPE_COMPLETE, 88 5184 ek110237 STRTYPE_INCOMPLETE, 89 5184 ek110237 STRTYPE_NULL, 90 5184 ek110237 STRTYPE_INVALID 91 5184 ek110237 } ac_strtype_t; 92 5184 ek110237 93 5184 ek110237 typedef struct ac_str { 94 5184 ek110237 const char *startp; 95 5184 ek110237 const char *endp; 96 5184 ek110237 ac_strtype_t strtype; 97 5184 ek110237 } ac_str_t; 98 5184 ek110237 99 5184 ek110237 #define STR_NUM 3 100 5184 ek110237 101 5184 ek110237 typedef struct ac_inputline { 102 5184 ek110237 ac_str_t strs[STR_NUM]; 103 5184 ek110237 } ac_inputline_t; 104 5184 ek110237 105 5184 ek110237 /* 106 5184 ek110237 * ac_iter represents a general interface to access a list of values for 107 5184 ek110237 * matching user input string. The structure has the following methods: 108 5184 ek110237 * 109 5184 ek110237 * bind - bind the iterator to a list, and save a pointer to user 110 5184 ek110237 * passed space in nlistpp. 111 5184 ek110237 * reset - reset internal index pointer to point to list head. 112 5184 ek110237 * get_nextstr - this is the method that does the real work. It 113 5184 ek110237 * walks through the list and returns string associated with 114 5184 ek110237 * the current item. It can also return some other thing the 115 5184 ek110237 * caller is interested via the user passed space pointed by 116 5184 ek110237 * nlistpp. In our case, that is a pointer to a list which 117 5184 ek110237 * contains all possible values for the next string in user 118 5184 ek110237 * input. 119 5184 ek110237 * 120 5184 ek110237 * It has the following data members: 121 5184 ek110237 * 122 5184 ek110237 * listp - a pointer to the list to be iterated through 123 5184 ek110237 * curp - index pointer to maintain position when iterating 124 5184 ek110237 * nlistpp - a pointer to user passed space for returning a list of 125 5184 ek110237 * values for the next string in user input 126 5184 ek110237 */ 127 5184 ek110237 128 5184 ek110237 typedef struct ac_iter { 129 5184 ek110237 void *listp; 130 5184 ek110237 void *curp; 131 5184 ek110237 void *nlistpp; 132 5184 ek110237 void (*bind)(struct ac_iter *, void *, void *); 133 5184 ek110237 void (*reset)(struct ac_iter *); 134 5184 ek110237 const char *(*get_nextstr)(struct ac_iter *); 135 5184 ek110237 } ac_iter_t; 136 5184 ek110237 137 5184 ek110237 /* 138 5184 ek110237 * We consider a filebench command is composed of a sequence of tokens 139 5184 ek110237 * (ie., command name, argument name, attribute name, etc.). Many of 140 5184 ek110237 * these tokens have limited string values. These values, as well as 141 5184 ek110237 * their dependencies, are used to complete user input string. 142 5184 ek110237 * 143 5184 ek110237 * There are the following tokens: 144 5184 ek110237 * 145 5184 ek110237 * TOKTYPE_CMD - command name 146 5184 ek110237 * TOKTYPE_ARG - argument name 147 5184 ek110237 * TOKTYPE_ATTRNAME - attribute name 148 5184 ek110237 * TOKTYPE_ATTRVAL - attribute value 149 5184 ek110237 * TOKTYPE_LVARNAME - variable name, used on left side of assign 150 5184 ek110237 * operator 151 5184 ek110237 * TOKTYPE_RVARNAME - variable name, used on right side of assign 152 5184 ek110237 * operator 153 5184 ek110237 * TOKTYPE_VARVAL - variable value 154 5184 ek110237 * TOKTYPE_LOADFILE - load file name 155 5184 ek110237 * TOKTYPE_ATTRLIST - pseudo token type for attribute list 156 5184 ek110237 * TOKTYPE_VARLIST - pseudo token type for variable list 157 5184 ek110237 * TOKTYPE_NULL - pseudo token type for aborting auto-completion 158 5184 ek110237 * 159 5184 ek110237 * The reason why there are two different token types for variable name 160 5184 ek110237 * is because, depending on its position, there are different requirements 161 5184 ek110237 * on how to do completion and display matching results. See more details 162 5184 ek110237 * in lvarname_iter and rvarname_iter definition. 163 5184 ek110237 * 164 5184 ek110237 * Attribute list and variable list are not really a single token. Instead 165 5184 ek110237 * they contain multiple tokens, and thus have different requirements on 166 5184 ek110237 * how to complete them. TOKTYPE_ATTRLIST and TOKTYPE_VARLIST are 167 5184 ek110237 * introduced to to solve this issue. See more details below on 168 5184 ek110237 * get_curtok() function in ac_tokinfo_t structure. 169 5184 ek110237 * 170 5184 ek110237 * ac_tokval_t represents a string value a token can have. The structure 171 5184 ek110237 * also contains a pointer to a ac_tvlist_t structure, which represents 172 5184 ek110237 * all possible values for the next token in the same command. 173 5184 ek110237 * 174 5184 ek110237 * str - the token's string value 175 5184 ek110237 * nlistp - a list which contains string values for the token 176 5184 ek110237 * that follows 177 5184 ek110237 * 178 5184 ek110237 * ac_tvlist_t represents all possible values for a token. These values 179 5184 ek110237 * are stored in an ac_tokval_t array. The structure also has a member 180 5184 ek110237 * toktype, which is used to index an ac_tokinfo_t array to get the 181 5184 ek110237 * information on how to access and use the associated value list. 182 5184 ek110237 * 183 5184 ek110237 * vals - a list of string values for this token 184 5184 ek110237 * toktype - the token's type 185 5184 ek110237 * 186 5184 ek110237 * ac_tokinfo_t contains information on how to access and use the 187 5184 ek110237 * string values of a specific token. Among them, the most important 188 5184 ek110237 * thing is an iterator to access the value list. The reason to use 189 5184 ek110237 * iterator is to encapsulate list implementation details. That is 190 5184 ek110237 * necessary because some tokens have dynamic values(for example, 191 5184 ek110237 * argument of load command), which cannot be predefined using 192 5184 ek110237 * ac_tokval_t array. 193 5184 ek110237 * 194 5184 ek110237 * ac_tokinfo_t structure has the following members: 195 5184 ek110237 * 196 5184 ek110237 * toktype - token type 197 5184 ek110237 * iter - iterator to access the token's value list 198 5184 ek110237 * cont_suffix - continuation suffix for this token. See note 1 199 5184 ek110237 * below on what is continuation suffix. 200 5184 ek110237 * get_curtok - a function to parse a multi-token user string. 201 5184 ek110237 * It parse that string and returns the word being 202 5184 ek110237 * completed and its token type. See note 2 below. 203 5184 ek110237 * 204 5184 ek110237 * Notes: 205 5184 ek110237 * 206 5184 ek110237 * 1) Continuation suffix is a convenient feature provided by libtecla. 207 5184 ek110237 * A continuation suffix is a string which is automatically appended 208 5184 ek110237 * to a fully completed string. For example, if a command name is 209 5184 ek110237 * fully completed, a blank space will be appended to it. This is 210 5184 ek110237 * very convenient because it not only saves typing, but also gives 211 5184 ek110237 * user an indication to continue. 212 5184 ek110237 * 213 5184 ek110237 * 2) get_curtok() function is a trick to support user input strings 214 5184 ek110237 * which have multiple tokens. Take attribute list as an example, 215 5184 ek110237 * although we defined a token type TOKTYPE_ATTRLIST for it, it is 216 5184 ek110237 * not a token actually, instead it contains multiple tokens like 217 5184 ek110237 * attribute name, attribute value, etc., and attribute value can 218 5184 ek110237 * be either a literal string or a variable name prefixed with a 219 5184 ek110237 * '$' sign. For this reason, get_curtok() function is needed to 220 5184 ek110237 * parse that string to get the word being completed and its token 221 5184 ek110237 * type so that we can match the word against with the proper value 222 5184 ek110237 * list. 223 5184 ek110237 */ 224 5184 ek110237 225 5184 ek110237 typedef enum ac_toktype { 226 5184 ek110237 TOKTYPE_CMD, 227 5184 ek110237 TOKTYPE_ARG, 228 5184 ek110237 TOKTYPE_ATTRNAME, 229 5184 ek110237 TOKTYPE_ATTRVAL, 230 5184 ek110237 TOKTYPE_LVARNAME, 231 5184 ek110237 TOKTYPE_RVARNAME, 232 5184 ek110237 TOKTYPE_VARVAL, 233 5184 ek110237 TOKTYPE_LOADFILE, 234 5184 ek110237 TOKTYPE_ATTRLIST, 235 5184 ek110237 TOKTYPE_VARLIST, 236 5184 ek110237 TOKTYPE_NULL 237 5184 ek110237 } ac_toktype_t; 238 5184 ek110237 239 5184 ek110237 typedef ac_toktype_t (*ac_get_curtok_func_t)(ac_str_t *); 240 5184 ek110237 241 5184 ek110237 typedef struct ac_tokinfo { 242 5184 ek110237 ac_toktype_t toktype; 243 5184 ek110237 ac_iter_t *iter; 244 5184 ek110237 char *cont_suffix; 245 5184 ek110237 ac_get_curtok_func_t get_curtok; 246 5184 ek110237 } ac_tokinfo_t; 247 5184 ek110237 248 5184 ek110237 typedef struct ac_tokval { 249 5184 ek110237 char *str; 250 5184 ek110237 struct ac_tvlist *nlistp; 251 5184 ek110237 } ac_tokval_t; 252 5184 ek110237 253 5184 ek110237 typedef struct ac_tvlist { 254 5184 ek110237 ac_tokval_t *vals; 255 5184 ek110237 ac_toktype_t toktype; 256 5184 ek110237 } ac_tvlist_t; 257 5184 ek110237 258 5184 ek110237 /* 259 5184 ek110237 * Variables and prototypes 260 5184 ek110237 */ 261 5184 ek110237 262 5184 ek110237 static void common_bind(ac_iter_t *, void *, void *); 263 5184 ek110237 static void common_reset(ac_iter_t *); 264 5184 ek110237 static void varname_bind(ac_iter_t *, void *, void *); 265 5184 ek110237 static void loadfile_bind(ac_iter_t *, void *, void *); 266 5184 ek110237 static const char *get_next_tokval(ac_iter_t *); 267 5184 ek110237 static const char *get_next_lvarname(ac_iter_t *); 268 5184 ek110237 static const char *get_next_rvarname(ac_iter_t *); 269 5184 ek110237 static const char *get_next_loadfile(ac_iter_t *); 270 5184 ek110237 static ac_toktype_t parse_attr_list(ac_str_t *); 271 5184 ek110237 static ac_toktype_t parse_var_list(ac_str_t *); 272 5184 ek110237 273 5184 ek110237 static ac_iter_t tokval_iter = { 274 5184 ek110237 NULL, 275 5184 ek110237 NULL, 276 5184 ek110237 NULL, 277 5184 ek110237 common_bind, 278 5184 ek110237 common_reset, 279 5184 ek110237 get_next_tokval 280 5184 ek110237 }; 281 5184 ek110237 282 5184 ek110237 static ac_iter_t lvarname_iter = { 283 5184 ek110237 NULL, 284 5184 ek110237 NULL, 285 5184 ek110237 NULL, 286 5184 ek110237 varname_bind, 287 5184 ek110237 common_reset, 288 5184 ek110237 get_next_lvarname 289 5184 ek110237 }; 290 5184 ek110237 291 5184 ek110237 static ac_iter_t rvarname_iter = { 292 5184 ek110237 NULL, 293 5184 ek110237 NULL, 294 5184 ek110237 NULL, 295 5184 ek110237 varname_bind, 296 5184 ek110237 common_reset, 297 5184 ek110237 get_next_rvarname 298 5184 ek110237 }; 299 5184 ek110237 300 5184 ek110237 static ac_iter_t loadfile_iter = { 301 5184 ek110237 NULL, 302 5184 ek110237 NULL, 303 5184 ek110237 NULL, 304 5184 ek110237 loadfile_bind, 305 5184 ek110237 common_reset, 306 5184 ek110237 get_next_loadfile 307 5184 ek110237 }; 308 5184 ek110237 309 5184 ek110237 /* 310 5184 ek110237 * Note: We use toktype to index into this array, so for each toktype, 311 5184 ek110237 * there must be one element in the array, and in the same order 312 5184 ek110237 * as that toktype is defined in ac_toktype. 313 5184 ek110237 */ 314 5184 ek110237 static ac_tokinfo_t token_info[] = { 315 5184 ek110237 { TOKTYPE_CMD, &tokval_iter, CSUF_CMD, NULL }, 316 5184 ek110237 { TOKTYPE_ARG, &tokval_iter, CSUF_ARG, NULL }, 317 5184 ek110237 { TOKTYPE_ATTRNAME, &tokval_iter, CSUF_ATTRNAME, NULL }, 318 5184 ek110237 { TOKTYPE_ATTRVAL, NULL, NULL, NULL }, 319 5184 ek110237 { TOKTYPE_LVARNAME, &lvarname_iter, CSUF_LVARNAME, NULL }, 320 5184 ek110237 { TOKTYPE_RVARNAME, &rvarname_iter, CSUF_RVARNAME, NULL }, 321 5184 ek110237 { TOKTYPE_VARVAL, NULL, NULL, NULL }, 322 5184 ek110237 { TOKTYPE_LOADFILE, &loadfile_iter, CSUF_ARG, NULL }, 323 5184 ek110237 { TOKTYPE_ATTRLIST, NULL, NULL, parse_attr_list }, 324 5184 ek110237 { TOKTYPE_VARLIST, NULL, NULL, parse_var_list }, 325 5184 ek110237 { TOKTYPE_NULL, NULL, NULL, NULL } 326 5184 ek110237 }; 327 5184 ek110237 328 5184 ek110237 static ac_tokval_t event_attrnames[] = { 329 5184 ek110237 { "rate", NULL}, 330 5184 ek110237 { NULL, NULL} 331 5184 ek110237 }; 332 5184 ek110237 333 5184 ek110237 static ac_tvlist_t event_attrs = { 334 5184 ek110237 event_attrnames, 335 5184 ek110237 TOKTYPE_ATTRLIST 336 5184 ek110237 }; 337 5184 ek110237 338 5184 ek110237 static ac_tokval_t file_attrnames[] = { 339 5184 ek110237 { "path", NULL }, 340 5184 ek110237 { "reuse", NULL }, 341 5184 ek110237 { "prealloc", NULL }, 342 5184 ek110237 { "paralloc", NULL }, 343 5184 ek110237 { NULL, NULL } 344 5184 ek110237 }; 345 5184 ek110237 346 5184 ek110237 static ac_tvlist_t file_attrs = { 347 5184 ek110237 file_attrnames, 348 5184 ek110237 TOKTYPE_ATTRLIST 349 5184 ek110237 }; 350 5184 ek110237 351 5184 ek110237 static ac_tokval_t fileset_attrnames[] = { 352 5184 ek110237 { "size", NULL }, 353 5184 ek110237 { "path", NULL }, 354 5184 ek110237 { "dirwidth", NULL }, 355 5184 ek110237 { "prealloc", NULL }, 356 5184 ek110237 { "filesizegamma", NULL }, 357 5184 ek110237 { "dirgamma", NULL }, 358 5184 ek110237 { "cached", NULL }, 359 5184 ek110237 { "entries", NULL }, 360 5184 ek110237 { NULL, NULL } 361 5184 ek110237 }; 362 5184 ek110237 363 5184 ek110237 static ac_tvlist_t fileset_attrs = { 364 5184 ek110237 fileset_attrnames, 365 5184 ek110237 TOKTYPE_ATTRLIST 366 5184 ek110237 }; 367 5184 ek110237 368 5184 ek110237 static ac_tokval_t process_attrnames[] = { 369 5184 ek110237 { "nice", NULL }, 370 5184 ek110237 { "instances", NULL }, 371 5184 ek110237 { NULL, NULL } 372 5184 ek110237 }; 373 5184 ek110237 374 5184 ek110237 static ac_tvlist_t process_attrs = { 375 5184 ek110237 process_attrnames, 376 5184 ek110237 TOKTYPE_ATTRLIST 377 5184 ek110237 }; 378 5184 ek110237 379 5184 ek110237 static ac_tokval_t create_argnames[] = { 380 5184 ek110237 { "file", NULL }, 381 5184 ek110237 { "fileset", NULL }, 382 5184 ek110237 { "process", NULL }, 383 5184 ek110237 { NULL, NULL } 384 5184 ek110237 }; 385 5184 ek110237 386 5184 ek110237 static ac_tvlist_t create_args = { 387 5184 ek110237 create_argnames, 388 5184 ek110237 TOKTYPE_ARG 389 5184 ek110237 }; 390 5184 ek110237 391 5184 ek110237 static ac_tokval_t define_argnames[] = { 392 5184 ek110237 { "file", &file_attrs }, 393 5184 ek110237 { "fileset", &fileset_attrs }, 394 5184 ek110237 { "process", &process_attrs }, 395 5184 ek110237 { NULL, NULL } 396 5184 ek110237 }; 397 5184 ek110237 398 5184 ek110237 static ac_tvlist_t define_args = { 399 5184 ek110237 define_argnames, 400 5184 ek110237 TOKTYPE_ARG 401 5184 ek110237 }; 402 5184 ek110237 403 5184 ek110237 static ac_tvlist_t load_args = { 404 5184 ek110237 NULL, 405 5184 ek110237 TOKTYPE_LOADFILE 406 5184 ek110237 }; 407 5184 ek110237 408 5184 ek110237 static ac_tvlist_t set_args = { 409 5184 ek110237 NULL, 410 5184 ek110237 TOKTYPE_VARLIST 411 5184 ek110237 }; 412 5184 ek110237 413 5184 ek110237 static ac_tokval_t shutdown_argnames[] = { 414 5184 ek110237 { "process", NULL }, 415 5184 ek110237 { NULL, NULL } 416 5184 ek110237 }; 417 5184 ek110237 418 5184 ek110237 static ac_tvlist_t shutdown_args = { 419 5184 ek110237 shutdown_argnames, 420 5184 ek110237 TOKTYPE_ARG 421 5184 ek110237 }; 422 5184 ek110237 423 5184 ek110237 static ac_tokval_t stats_argnames[] = { 424 5184 ek110237 { "clear", NULL }, 425 5184 ek110237 { "directory", NULL }, 426 5184 ek110237 { "command", NULL }, 427 5184 ek110237 { "dump", NULL }, 428 5184 ek110237 { "xmldump", NULL }, 429 5184 ek110237 { NULL, NULL } 430 5184 ek110237 }; 431 5184 ek110237 432 5184 ek110237 static ac_tvlist_t stats_args = { 433 5184 ek110237 stats_argnames, 434 5184 ek110237 TOKTYPE_ARG 435 5184 ek110237 }; 436 5184 ek110237 437 5184 ek110237 static ac_tokval_t fb_cmdnames[] = { 438 5184 ek110237 { "create", &create_args }, 439 5184 ek110237 { "define", &define_args }, 440 5184 ek110237 { "debug", NULL }, 441 5184 ek110237 { "echo", NULL }, 442 5184 ek110237 { "eventgen", &event_attrs }, 443 5184 ek110237 { "foreach", NULL }, 444 5184 ek110237 { "help", NULL }, 445 5184 ek110237 { "list", NULL }, 446 5184 ek110237 { "load", &load_args }, 447 5184 ek110237 { "log", NULL }, 448 5184 ek110237 { "quit", NULL }, 449 5184 ek110237 { "run", NULL }, 450 5184 ek110237 { "set", &set_args }, 451 5184 ek110237 { "shutdown", &shutdown_args }, 452 5184 ek110237 { "sleep", NULL }, 453 5184 ek110237 { "stats", &stats_args }, 454 5184 ek110237 { "system", NULL }, 455 5184 ek110237 { "usage", NULL }, 456 5184 ek110237 { "vars", NULL }, 457 6750 ek110237 { "version", NULL }, 458 5184 ek110237 { NULL, NULL }, 459 5184 ek110237 }; 460 5184 ek110237 461 5184 ek110237 static ac_tvlist_t fb_cmds = { 462 5184 ek110237 fb_cmdnames, 463 5184 ek110237 TOKTYPE_CMD 464 5184 ek110237 }; 465 5184 ek110237 466 5184 ek110237 static ac_fname_cache_t loadnames = { NULL, 0, 0 }; 467 5184 ek110237 468 5184 ek110237 static int search_loadfiles(ac_fname_cache_t *); 469 5184 ek110237 static void parse_user_input(const char *, int, ac_inputline_t *); 470 5184 ek110237 static int compare_string(ac_str_t *, const char *, boolean_t, const char **); 471 5184 ek110237 static ac_match_result_t match_string(WordCompletion *, const char *, int, 472 5184 ek110237 ac_str_t *, ac_iter_t *, const char *); 473 5184 ek110237 474 5184 ek110237 /* 475 5184 ek110237 * Bind the iterator to the passed list 476 5184 ek110237 */ 477 5184 ek110237 static void 478 5184 ek110237 common_bind(ac_iter_t *iterp, void *listp, void *nlistpp) 479 5184 ek110237 { 480 5184 ek110237 iterp->listp = listp; 481 5184 ek110237 iterp->nlistpp = nlistpp; 482 5184 ek110237 } 483 5184 ek110237 484 5184 ek110237 /* 485 5184 ek110237 * Reset index pointer to point to list head 486 5184 ek110237 */ 487 5184 ek110237 static void 488 5184 ek110237 common_reset(ac_iter_t *iterp) 489 5184 ek110237 { 490 5184 ek110237 iterp->curp = iterp->listp; 491 5184 ek110237 } 492 5184 ek110237 493 5184 ek110237 /* 494 5184 ek110237 * Walk through an array of ac_tokval_t structures and return string 495 5184 ek110237 * of each item. 496 5184 ek110237 */ 497 5184 ek110237 static const char * 498 5184 ek110237 get_next_tokval(ac_iter_t *iterp) 499 5184 ek110237 { 500 5184 ek110237 ac_tokval_t *listp = iterp->listp; /* list head */ 501 5184 ek110237 ac_tokval_t *curp = iterp->curp; /* index pointer */ 502 5184 ek110237 /* user passed variable for returning value list for next token */ 503 5184 ek110237 ac_tvlist_t **nlistpp = iterp->nlistpp; 504 5184 ek110237 const char *p; 505 5184 ek110237 506 5184 ek110237 if (listp == NULL || curp == NULL) 507 5184 ek110237 return (NULL); 508 5184 ek110237 509 5184 ek110237 /* get the current item's string */ 510 5184 ek110237 p = curp->str; 511 5184 ek110237 512 5184 ek110237 /* 513 5184 ek110237 * save the current item's address into a user passed variable 514 5184 ek110237 */ 515 5184 ek110237 if (nlistpp != NULL) 516 5184 ek110237 *nlistpp = curp->nlistp; 517 5184 ek110237 518 5184 ek110237 /* advance the index pointer */ 519 5184 ek110237 iterp->curp = ++curp; 520 5184 ek110237 521 5184 ek110237 return (p); 522 5184 ek110237 } 523 5184 ek110237 524 5184 ek110237 /* 525 6391 aw148015 * Bind the iterator to filebench_shm->shm_var_list 526 5184 ek110237 */ 527 6391 aw148015 /* ARGSUSED */ 528 5184 ek110237 static void 529 5184 ek110237 varname_bind(ac_iter_t *iterp, void *listp, void * nlistpp) 530 5184 ek110237 { 531 6391 aw148015 iterp->listp = filebench_shm->shm_var_list; 532 5184 ek110237 iterp->nlistpp = nlistpp; 533 5184 ek110237 } 534 5184 ek110237 535 5184 ek110237 /* 536 5184 ek110237 * Walk through a linked list of var_t type structures and return name 537 5184 ek110237 * of each variable with a preceding '$' sign 538 5184 ek110237 */ 539 5184 ek110237 static const char * 540 5184 ek110237 get_next_lvarname(ac_iter_t *iterp) 541 5184 ek110237 { 542 5184 ek110237 static char buf[VARNAME_MAXLEN]; 543 5184 ek110237 544 5184 ek110237 var_t *listp = iterp->listp; /* list head */ 545 5184 ek110237 var_t *curp = iterp->curp; /* index pointer */ 546 5184 ek110237 /* User passed variable for returning value list for next token */ 547 5184 ek110237 ac_tvlist_t **nlistpp = iterp->nlistpp; 548 5184 ek110237 const char *p; 549 5184 ek110237 550 5184 ek110237 if (listp == NULL || curp == NULL) 551 5184 ek110237 return (NULL); 552 5184 ek110237 553 5184 ek110237 /* Get current variable's name, copy it to buf, with a '$' prefix */ 554 5184 ek110237 p = curp->var_name; 555 5184 ek110237 (void) snprintf(buf, sizeof (buf), "$%s", p); 556 5184 ek110237 557 5184 ek110237 /* No information for the next input string */ 558 5184 ek110237 if (nlistpp != NULL) 559 5184 ek110237 *nlistpp = NULL; 560 5184 ek110237 561 5184 ek110237 /* Advance the index pointer */ 562 5184 ek110237 iterp->curp = curp->var_next; 563 5184 ek110237 564 5184 ek110237 return (buf); 565 5184 ek110237 } 566 5184 ek110237 567 5184 ek110237 /* 568 5184 ek110237 * Walk through a linked list of var_t type structures and return name 569 5184 ek110237 * of each variable 570 5184 ek110237 */ 571 5184 ek110237 static const char * 572 5184 ek110237 get_next_rvarname(ac_iter_t *iterp) 573 5184 ek110237 { 574 5184 ek110237 var_t *listp = iterp->listp; /* list head */ 575 5184 ek110237 var_t *curp = iterp->curp; /* index pointer */ 576 5184 ek110237 /* User passed variable for returning value list for next item */ 577 5184 ek110237 ac_tvlist_t **nlistpp = iterp->nlistpp; 578 5184 ek110237 const char *p; 579 5184 ek110237 580 5184 ek110237 if (listp == NULL || curp == NULL) 581 5184 ek110237 return (NULL); 582 5184 ek110237 583 5184 ek110237 /* Get current variable's name */ 584 5184 ek110237 p = curp->var_name; 585 5184 ek110237 586 5184 ek110237 /* No information for the next input string */ 587 5184 ek110237 if (nlistpp != NULL) 588 5184 ek110237 *nlistpp = NULL; 589 5184 ek110237 590 5184 ek110237 /* Advance the index pointer */ 591 5184 ek110237 iterp->curp = curp->var_next; 592 5184 ek110237 593 5184 ek110237 return (p); 594 5184 ek110237 } 595 5184 ek110237 596 5184 ek110237 /* 597 5184 ek110237 * Bind the iterator to loadnames.fnc_buf, which is an ac_fname_t array 598 5184 ek110237 * and contains up-to-date workload file names. The function calls 599 5184 ek110237 * search_loadfiles() to update the cache before the binding. 600 5184 ek110237 */ 601 6391 aw148015 /* ARGSUSED */ 602 5184 ek110237 static void 603 5184 ek110237 loadfile_bind(ac_iter_t *iterp, void *listp, void * nlistpp) 604 5184 ek110237 { 605 5184 ek110237 /* Check loadfile name cache, update it if needed */ 606 5184 ek110237 (void) search_loadfiles(&loadnames); 607 5184 ek110237 608 5184 ek110237 iterp->listp = loadnames.fnc_buf; 609 5184 ek110237 iterp->nlistpp = nlistpp; 610 5184 ek110237 } 611 5184 ek110237 612 5184 ek110237 /* 613 5184 ek110237 * Walk through a string(ac_fname_t, more exactly) array and return each 614 5184 ek110237 * string, until a NULL iterm is encountered. 615 5184 ek110237 */ 616 5184 ek110237 static const char * 617 5184 ek110237 get_next_loadfile(ac_iter_t *iterp) 618 5184 ek110237 { 619 5184 ek110237 ac_fname_t *listp = iterp->listp; /* list head */ 620 5184 ek110237 ac_fname_t *curp = iterp->curp; /* index pointer */ 621 5184 ek110237 /* User passed variable for returning value list for next item */ 622 5184 ek110237 ac_tvlist_t **nlistpp = iterp->nlistpp; 623 5184 ek110237 const char *p; 624 5184 ek110237 625 5184 ek110237 if (listp == NULL || curp == NULL) 626 5184 ek110237 return (NULL); 627 5184 ek110237 628 5184 ek110237 /* 629 5184 ek110237 * Get current file name. If an NULL item is encountered, it means 630 5184 ek110237 * this is the end of the list. In that case, we need to set p to 631 5184 ek110237 * NULL to indicate to the caller that the end of the list is reached. 632 5184 ek110237 */ 633 5184 ek110237 p = (char *)curp; 634 5184 ek110237 if (*p == NULL) 635 5184 ek110237 p = NULL; 636 5184 ek110237 637 5184 ek110237 /* No information for the next input string */ 638 5184 ek110237 if (nlistpp != NULL) 639 5184 ek110237 *nlistpp = NULL; 640 5184 ek110237 641 5184 ek110237 /* Advance the index pointer */ 642 5184 ek110237 iterp->curp = ++curp; 643 5184 ek110237 644 5184 ek110237 return (p); 645 5184 ek110237 } 646 5184 ek110237 647 5184 ek110237 /* 648 5184 ek110237 * Search for available workload files in workload direcotry and 649 5184 ek110237 * update workload name cache. 650 5184 ek110237 */ 651 5184 ek110237 static int 652 5184 ek110237 search_loadfiles(ac_fname_cache_t *fnamecache) 653 5184 ek110237 { 654 5184 ek110237 DIR *dirp; 655 5184 ek110237 struct dirent *fp; 656 5184 ek110237 struct stat dstat; 657 5184 ek110237 time_t mtime; 658 5184 ek110237 ac_fname_t *buf; 659 5184 ek110237 int bufsize = MALLOC_STEP; 660 5184 ek110237 int len, i; 661 5184 ek110237 662 5184 ek110237 if (stat(FILEBENCHDIR"/workloads", &dstat) != 0) 663 5184 ek110237 return (-1); 664 5184 ek110237 mtime = dstat.st_mtime; 665 5184 ek110237 666 5184 ek110237 /* Return if there is no change since last time */ 667 5184 ek110237 if (mtime == fnamecache->fnc_mtime) 668 5184 ek110237 return (0); 669 5184 ek110237 670 5184 ek110237 /* Get loadfile names and cache it */ 671 5184 ek110237 if ((buf = malloc(sizeof (ac_fname_t) * bufsize)) == NULL) 672 5184 ek110237 return (-1); 673 5184 ek110237 if ((dirp = opendir(FILEBENCHDIR"/workloads")) == NULL) 674 5184 ek110237 return (-1); 675 5184 ek110237 i = 0; 676 5184 ek110237 while ((fp = readdir(dirp)) != NULL) { 677 5184 ek110237 len = strlen(fp->d_name); 678 5184 ek110237 if (len <= 2 || (fp->d_name)[len - 2] != '.' || 679 5184 ek110237 (fp->d_name)[len - 1] != 'f') 680 5184 ek110237 continue; 681 5184 ek110237 682 5184 ek110237 if (i == bufsize) { 683 5184 ek110237 bufsize += MALLOC_STEP; 684 5184 ek110237 if ((buf = realloc(buf, sizeof (ac_fname_t) * 685 5184 ek110237 bufsize)) == NULL) 686 5184 ek110237 return (-1); 687 5184 ek110237 } 688 5184 ek110237 689 5184 ek110237 (void) snprintf(buf[i], FILENAME_MAXLEN, "%s", fp->d_name); 690 5184 ek110237 if (len -2 <= FILENAME_MAXLEN - 1) { 691 5184 ek110237 /* Remove .f suffix in file name */ 692 5184 ek110237 buf[i][len -2] = NULL; 693 5184 ek110237 } 694 5184 ek110237 i++; 695 5184 ek110237 } 696 5184 ek110237 /* Added a NULL iterm as the array's terminator */ 697 5184 ek110237 buf[i][0] = NULL; 698 5184 ek110237 699 5184 ek110237 if (fnamecache->fnc_bufsize != 0) 700 5184 ek110237 free(fnamecache->fnc_buf); 701 5184 ek110237 fnamecache->fnc_buf = buf; 702 5184 ek110237 fnamecache->fnc_bufsize = bufsize; 703 5184 ek110237 fnamecache->fnc_mtime = mtime; 704 5184 ek110237 705 5184 ek110237 return (0); 706 5184 ek110237 } 707 5184 ek110237 708 5184 ek110237 /* 709 5184 ek110237 * Parse user input line into a list of blank separated strings, and 710 5184 ek110237 * save the result in the passed ac_inputline_t structure. line and word_end 711 5184 ek110237 * parameters are passed from libtecla library. line points to user input 712 5184 ek110237 * buffer, and word_end is the index of the last character of user input. 713 5184 ek110237 */ 714 6391 aw148015 /* ARGSUSED */ 715 5184 ek110237 static void 716 5184 ek110237 parse_user_input(const char *line, int word_end, ac_inputline_t *input) 717 5184 ek110237 { 718 5184 ek110237 const char *p = line; 719 5184 ek110237 int i; 720 5184 ek110237 721 5184 ek110237 /* Reset all fileds */ 722 5184 ek110237 for (i = 0; i < STR_NUM; i++) { 723 5184 ek110237 input->strs[i].startp = NULL; 724 5184 ek110237 input->strs[i].endp = NULL; 725 5184 ek110237 input->strs[i].strtype = STRTYPE_INVALID; 726 5184 ek110237 } 727 5184 ek110237 728 5184 ek110237 /* 729 5184 ek110237 * Parse user input. We don't use word_end to do boundary checking, 730 5184 ek110237 * instead we take advantage of the fact that the passed line 731 5184 ek110237 * parameter is always terminated by '\0'. 732 5184 ek110237 */ 733 5184 ek110237 for (i = 0; i < STR_NUM; i++) { 734 5184 ek110237 /* Skip leading blank spaces */ 735 5184 ek110237 while (*p == ' ') 736 5184 ek110237 p++; 737 5184 ek110237 738 5184 ek110237 if (*p == NULL) { 739 5184 ek110237 /* 740 5184 ek110237 * User input nothing for the string being input 741 5184 ek110237 * before he pressed TAB. We use STR_NULL flag 742 5184 ek110237 * to indicate this so that match_str() will list 743 5184 ek110237 * all available candidates. 744 5184 ek110237 */ 745 5184 ek110237 input->strs[i].startp = p; 746 5184 ek110237 input->strs[i].strtype = STRTYPE_NULL; 747 5184 ek110237 return; 748 5184 ek110237 } 749 5184 ek110237 750 5184 ek110237 /* Recoard the start and end of the string */ 751 5184 ek110237 input->strs[i].startp = p; 752 5184 ek110237 while ((*p != ' ') && (*p != NULL)) 753 5184 ek110237 p++; 754 5184 ek110237 input->strs[i].endp = p - 1; 755 5184 ek110237 756 5184 ek110237 if (*p == NULL) { 757 5184 ek110237 input->strs[i].strtype = STRTYPE_INCOMPLETE; 758 5184 ek110237 return; 759 5184 ek110237 } else { 760 5184 ek110237 /* The string is followed by a blank space */ 761 5184 ek110237 input->strs[i].strtype = STRTYPE_COMPLETE; 762 5184 ek110237 } 763 5184 ek110237 } 764 5184 ek110237 } 765 5184 ek110237 766 5184 ek110237 /* 767 5184 ek110237 * Parse an input string which is an attribue list, get the current word 768 5184 ek110237 * user wants to complete, and return its token type. 769 5184 ek110237 * 770 5184 ek110237 * An atribute list has the following format: 771 5184 ek110237 * 772 5184 ek110237 * name1=val,name2=$var,... 773 5184 ek110237 * 774 5184 ek110237 * The function modifies the passed acstr string on success to point to 775 5184 ek110237 * the word being completed. 776 5184 ek110237 */ 777 5184 ek110237 static ac_toktype_t 778 5184 ek110237 parse_attr_list(ac_str_t *acstr) 779 5184 ek110237 { 780 5184 ek110237 const char *p; 781 5184 ek110237 782 5184 ek110237 if (acstr->strtype == STRTYPE_COMPLETE) { 783 5184 ek110237 /* 784 5184 ek110237 * User has input a complete string for attribute list 785 5184 ek110237 * return TOKTYPE_NULL to abort the matching. 786 5184 ek110237 */ 787 5184 ek110237 return (TOKTYPE_ATTRLIST); 788 5184 ek110237 } else if (acstr->strtype == STRTYPE_NULL) { 789 5184 ek110237 /* 790 5184 ek110237 * User haven't input anything for the attribute list, 791 5184 ek110237 * he must be trying to list all attribute names. 792 5184 ek110237 */ 793 5184 ek110237 return (TOKTYPE_ATTRNAME); 794 5184 ek110237 } 795 5184 ek110237 796 5184 ek110237 /* 797 5184 ek110237 * The string may contain multiple comma separated "name=value" 798 5184 ek110237 * items. Try to find the last one and move startp to point to it. 799 5184 ek110237 */ 800 5184 ek110237 for (p = acstr->endp; p >= acstr->startp && *p != ATTR_LIST_SEP; p--) {} 801 5184 ek110237 802 5184 ek110237 if (p == acstr->endp) { 803 5184 ek110237 /* 804 5184 ek110237 * The last character of the string is ',', which means 805 5184 ek110237 * user is trying to list all attribute names. 806 5184 ek110237 */ 807 5184 ek110237 acstr->startp = p + 1; 808 5184 ek110237 acstr->strtype = STRTYPE_NULL; 809 5184 ek110237 return (TOKTYPE_ATTRNAME); 810 5184 ek110237 } else if (p > acstr->startp) { 811 5184 ek110237 /* 812 5184 ek110237 * Found ',' between starp and endp, move startp pointer 813 5184 ek110237 * to point to the last item. 814 5184 ek110237 */ 815 5184 ek110237 acstr->startp = p + 1; 816 5184 ek110237 } 817 5184 ek110237 818 5184 ek110237 /* 819 5184 ek110237 * Now startp points to the last "name=value" item. Search in 820 5184 ek110237 * the characters user has input for this item: 821 5184 ek110237 * 822 5184 ek110237 * a) if there isn't '=' character, user is inputting attribute name 823 5184 ek110237 * b) if there is a '=' character and it is followed by a '$', 824 5184 ek110237 * user is inputting variable name 825 5184 ek110237 * c) if there is a '=' character and it isn't followed by a '$', 826 5184 ek110237 * user is inputting a literal string as attribute value. 827 5184 ek110237 */ 828 5184 ek110237 for (p = acstr->startp; p <= acstr->endp; p++) { 829 5184 ek110237 if (*p == ATTR_ASSIGN_OP) { 830 5184 ek110237 /* Found "=" operator in the string */ 831 5184 ek110237 if (*(p + 1) == VAR_PREFIX) { 832 5184 ek110237 acstr->startp = p + 2; 833 5184 ek110237 if (*acstr->startp != NULL) 834 5184 ek110237 acstr->strtype = STRTYPE_INCOMPLETE; 835 5184 ek110237 else 836 5184 ek110237 acstr->strtype = STRTYPE_NULL; 837 5184 ek110237 return (TOKTYPE_RVARNAME); 838 5184 ek110237 } else { 839 5184 ek110237 return (TOKTYPE_ATTRVAL); 840 5184 ek110237 } 841 5184 ek110237 } 842 5184 ek110237 } 843 5184 ek110237 844 5184 ek110237 /* Didn't find '=' operator, the string must be an attribute name */ 845 5184 ek110237 return (TOKTYPE_ATTRNAME); 846 5184 ek110237 } 847 5184 ek110237 848 5184 ek110237 /* 849 5184 ek110237 * Parse an input string which is a variable list, get the current word 850 5184 ek110237 * user wants to complete, and return its token type. 851 5184 ek110237 * 852 5184 ek110237 * A varaible list has the following format: 853 5184 ek110237 * 854 5184 ek110237 * $varname=value 855 5184 ek110237 * 856 5184 ek110237 * The function modifies the passed acstr string on success to point to 857 5184 ek110237 * the word being completed. 858 5184 ek110237 */ 859 5184 ek110237 static ac_toktype_t 860 5184 ek110237 parse_var_list(ac_str_t *acstr) 861 5184 ek110237 { 862 5184 ek110237 const char *p; 863 5184 ek110237 864 5184 ek110237 if (acstr->strtype == STRTYPE_COMPLETE) { 865 5184 ek110237 /* 866 5184 ek110237 * User has input a complete string for var list 867 5184 ek110237 * return TOKTYPE_NULL to abort the matching. 868 5184 ek110237 */ 869 5184 ek110237 return (TOKTYPE_NULL); 870 5184 ek110237 } else if (acstr->strtype == STRTYPE_NULL) { 871 5184 ek110237 /* 872 5184 ek110237 * User haven't input anything for the attribute list, 873 5184 ek110237 * he must be trying to list all available var names. 874 5184 ek110237 */ 875 5184 ek110237 return (TOKTYPE_LVARNAME); 876 5184 ek110237 } 877 5184 ek110237 878 5184 ek110237 /* 879 5184 ek110237 * Search in what user has input: 880 5184 ek110237 * 881 5184 ek110237 * a) if there isn't a '=' character, user is inputting var name 882 5184 ek110237 * b) if there is a '=' character, user is inputting var value 883 5184 ek110237 */ 884 5184 ek110237 for (p = acstr->startp; p <= acstr->endp; p++) { 885 5184 ek110237 if (*p == VAR_ASSIGN_OP) 886 5184 ek110237 return (TOKTYPE_VARVAL); 887 5184 ek110237 } 888 5184 ek110237 889 5184 ek110237 /* Didn't find '=' operator, user must be inputting an var name */ 890 5184 ek110237 return (TOKTYPE_LVARNAME); 891 5184 ek110237 } 892 5184 ek110237 893 5184 ek110237 /* 894 5184 ek110237 * Compare two strings acstr and str. acstr is a string of ac_str_t type, 895 5184 ek110237 * str is a normal string. If issub is B_TRUE, the function checks if 896 5184 ek110237 * acstr is a sub-string of str, starting from index 0; otherwise it checks 897 5184 ek110237 * if acstr and str are exactly the same. 898 5184 ek110237 * 899 5184 ek110237 * The function returns 0 on success and -1 on failure. When it succeeds, 900 5184 ek110237 * it also set restp to point to the rest part of the normal string. 901 5184 ek110237 */ 902 5184 ek110237 static int 903 5184 ek110237 compare_string(ac_str_t *acstr, const char *str, boolean_t issub, 904 5184 ek110237 const char **restp) 905 5184 ek110237 { 906 5184 ek110237 const char *p, *q; 907 5184 ek110237 908 5184 ek110237 for (p = acstr->startp, q = str; (p <= acstr->endp) && (*q != '\0'); 909 5184 ek110237 p++, q++) { 910 5184 ek110237 if (*p != *q) 911 5184 ek110237 return (-1); 912 5184 ek110237 } 913 5184 ek110237 914 5184 ek110237 if (p == acstr->endp + 1) { 915 5184 ek110237 if (*q == '\0' || issub == B_TRUE) { 916 5184 ek110237 if (restp != NULL) 917 5184 ek110237 *restp = q; 918 5184 ek110237 return (0); 919 5184 ek110237 } 920 5184 ek110237 } 921 5184 ek110237 922 5184 ek110237 return (-1); 923 5184 ek110237 } 924 5184 ek110237 925 5184 ek110237 /* 926 5184 ek110237 * Use the passed iterp iterator to access a list of string values to 927 5184 ek110237 * look for those matches with acstr, an user input string to be completed. 928 5184 ek110237 * 929 5184 ek110237 * cpl, line, work_end, and cont_suffix are parameters needed by 930 5184 ek110237 * cpl_add_completion(), which adds matched entries to libtecla. 931 5184 ek110237 * 932 5184 ek110237 * Since user input line may have multiple strings, the function is 933 5184 ek110237 * expected to be called multiple times to match those strings one 934 5184 ek110237 * by one until the last one is reached. 935 5184 ek110237 * 936 5184 ek110237 * The multi-step matching process also means the function should provide 937 5184 ek110237 * a way to indicate to the caller whether to continue or abort the 938 5184 ek110237 * whole matching process. The function does that with the following 939 5184 ek110237 * return values: 940 5184 ek110237 * 941 5184 ek110237 * MATCH_DONE - the matching for the whole user input is done. This 942 5184 ek110237 * can mean either some items are found or none is found. 943 5184 ek110237 * In either case, the caller shouldn't continue to 944 5184 ek110237 * match the rest strings, either because there is 945 5184 ek110237 * no strings left, or because the matching for the 946 5184 ek110237 * current string failed so there is no need to check 947 5184 ek110237 * further. 948 5184 ek110237 * MATCH_CONT - the matching for the current string succeeds, but 949 5184 ek110237 * user needs to continue to match the rest strings. 950 5184 ek110237 */ 951 5184 ek110237 static ac_match_result_t 952 5184 ek110237 match_string(WordCompletion *cpl, const char *line, int word_end, 953 5184 ek110237 ac_str_t *acstr, ac_iter_t *iterp, const char *cont_suffix) 954 5184 ek110237 { 955 5184 ek110237 const char *str, *restp; 956 5184 ek110237 957 5184 ek110237 iterp->reset(iterp); 958 5184 ek110237 959 5184 ek110237 if (acstr->strtype == STRTYPE_COMPLETE) { 960 5184 ek110237 while ((str = iterp->get_nextstr(iterp)) != NULL) { 961 5184 ek110237 if (!compare_string(acstr, str, B_FALSE, NULL)) { 962 5184 ek110237 /* Continue to check rest strings */ 963 5184 ek110237 return (MATCH_CONT); 964 5184 ek110237 } 965 5184 ek110237 } 966 5184 ek110237 } else if (acstr->strtype == STRTYPE_NULL) { 967 5184 ek110237 /* User input nothing. List all available strings */ 968 5184 ek110237 while ((str = iterp->get_nextstr(iterp)) != NULL) { 969 5184 ek110237 (void) cpl_add_completion(cpl, line, 970 5184 ek110237 acstr->startp - line, word_end, str, 971 5184 ek110237 NULL, cont_suffix); 972 5184 ek110237 } 973 5184 ek110237 } else if (acstr->strtype == STRTYPE_INCOMPLETE) { 974 5184 ek110237 while ((str = iterp->get_nextstr(iterp)) != NULL) { 975 5184 ek110237 if (!compare_string(acstr, str, B_TRUE, &restp)) { 976 5184 ek110237 /* It matches! Add it. */ 977 5184 ek110237 (void) cpl_add_completion(cpl, line, 978 5184 ek110237 acstr->startp - line, word_end, restp, 979 5184 ek110237 NULL, cont_suffix); 980 5184 ek110237 } 981 5184 ek110237 } 982 5184 ek110237 } 983 5184 ek110237 984 5184 ek110237 return (MATCH_DONE); 985 5184 ek110237 } 986 5184 ek110237 987 5184 ek110237 /* 988 5184 ek110237 * This is the interface between filebench and libtecla for auto- 989 5184 ek110237 * completion. It is called by libtecla whenever user initiates a 990 5184 ek110237 * auto-completion request(ie., pressing TAB key). 991 5184 ek110237 * 992 5184 ek110237 * The function calls parse_user_input() to parse user input into 993 5184 ek110237 * multiple strings, then it calls match_string() to match each 994 5184 ek110237 * string in user input in sequence until either the last string 995 5184 ek110237 * is reached and completed or the the matching fails. 996 5184 ek110237 */ 997 6391 aw148015 /* ARGSUSED */ 998 5184 ek110237 CPL_MATCH_FN(command_complete) 999 5184 ek110237 { 1000 5184 ek110237 ac_inputline_t inputline; 1001 5184 ek110237 ac_tvlist_t *clistp = &fb_cmds, *nlistp; 1002 5184 ek110237 ac_toktype_t toktype; 1003 5184 ek110237 ac_iter_t *iterp; 1004 5184 ek110237 char *cont_suffix; 1005 5184 ek110237 ac_get_curtok_func_t get_curtok; 1006 5184 ek110237 int i, ret; 1007 5184 ek110237 1008 5184 ek110237 /* Parse user input and save the result in inputline variable. */ 1009 5184 ek110237 parse_user_input(line, word_end, &inputline); 1010 5184 ek110237 1011 5184 ek110237 /* 1012 5184 ek110237 * Match each string in user input against the proper token's 1013 5184 ek110237 * value list, and continue the loop until either the last string 1014 5184 ek110237 * is reached and completed or the matching aborts. 1015 5184 ek110237 */ 1016 5184 ek110237 for (i = 0; i < STR_NUM && 1017 5184 ek110237 inputline.strs[i].strtype != STRTYPE_INVALID && clistp != NULL; 1018 5184 ek110237 i++) { 1019 5184 ek110237 toktype = clistp->toktype; 1020 5184 ek110237 1021 5184 ek110237 /* 1022 5184 ek110237 * If the current stirng can contain multiple tokens, modify 1023 5184 ek110237 * the stirng to point to the word being input and return 1024 5184 ek110237 * its token type. 1025 5184 ek110237 */ 1026 5184 ek110237 get_curtok = token_info[toktype].get_curtok; 1027 5184 ek110237 if (get_curtok != NULL) 1028 5184 ek110237 toktype = (*get_curtok)(&inputline.strs[i]); 1029 5184 ek110237 1030 5184 ek110237 iterp = token_info[toktype].iter; 1031 5184 ek110237 cont_suffix = token_info[toktype].cont_suffix; 1032 5184 ek110237 /* Return if there is no completion info for the token */ 1033 5184 ek110237 if (iterp == NULL) 1034 5184 ek110237 break; 1035 5184 ek110237 1036 5184 ek110237 iterp->bind(iterp, clistp->vals, &nlistp); 1037 5184 ek110237 /* Match user string against the token's list */ 1038 5184 ek110237 ret = match_string(cpl, line, word_end, &inputline.strs[i], 1039 5184 ek110237 iterp, cont_suffix); 1040 5184 ek110237 if (ret == MATCH_DONE) 1041 5184 ek110237 return (0); 1042 5184 ek110237 clistp = nlistp; 1043 5184 ek110237 } 1044 5184 ek110237 1045 5184 ek110237 return (0); 1046 5184 ek110237 } 1047