00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00040 #include <console/kconsole.h>
00041 #include <console/console.h>
00042 #include <console/chardev.h>
00043 #include <console/cmd.h>
00044 #include <print.h>
00045 #include <panic.h>
00046 #include <typedefs.h>
00047 #include <arch/types.h>
00048 #include <adt/list.h>
00049 #include <arch.h>
00050 #include <macros.h>
00051 #include <debug.h>
00052 #include <func.h>
00053 #include <symtab.h>
00054 #include <macros.h>
00055
00079 SPINLOCK_INITIALIZE(cmd_lock);
00080 LIST_INITIALIZE(cmd_head);
00082 static cmd_info_t *parse_cmdline(char *cmdline, size_t len);
00083 static bool parse_argument(char *cmdline, size_t len, index_t *start, index_t *end);
00084 static char history[KCONSOLE_HISTORY][MAX_CMDLINE] = {};
00085
00087 void kconsole_init(void)
00088 {
00089 int i;
00090
00091 cmd_init();
00092 for (i=0; i<KCONSOLE_HISTORY; i++)
00093 history[i][0] = '\0';
00094 }
00095
00096
00103 int cmd_register(cmd_info_t *cmd)
00104 {
00105 link_t *cur;
00106
00107 spinlock_lock(&cmd_lock);
00108
00109
00110
00111
00112 for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
00113 cmd_info_t *hlp;
00114
00115 hlp = list_get_instance(cur, cmd_info_t, link);
00116
00117 if (hlp == cmd) {
00118
00119 spinlock_unlock(&cmd_lock);
00120 return 0;
00121 }
00122
00123
00124 if (hlp < cmd) {
00125 spinlock_lock(&hlp->lock);
00126 spinlock_lock(&cmd->lock);
00127 } else {
00128 spinlock_lock(&cmd->lock);
00129 spinlock_lock(&hlp->lock);
00130 }
00131 if ((strncmp(hlp->name,
00132 cmd->name, max(strlen(cmd->name),
00133 strlen(hlp->name))) == 0)) {
00134
00135 spinlock_unlock(&hlp->lock);
00136 spinlock_unlock(&cmd->lock);
00137 spinlock_unlock(&cmd_lock);
00138 return 0;
00139 }
00140
00141 spinlock_unlock(&hlp->lock);
00142 spinlock_unlock(&cmd->lock);
00143 }
00144
00145
00146
00147
00148 list_append(&cmd->link, &cmd_head);
00149
00150 spinlock_unlock(&cmd_lock);
00151 return 1;
00152 }
00153
00155 static void rdln_print_c(char ch, int count)
00156 {
00157 int i;
00158 for (i=0;i<count;i++)
00159 putchar(ch);
00160 }
00161
00163 static void insert_char(char *str, char ch, int pos)
00164 {
00165 int i;
00166
00167 for (i=strlen(str);i > pos; i--)
00168 str[i] = str[i-1];
00169 str[pos] = ch;
00170 }
00171
00173 static const char * cmdtab_search_one(const char *name,link_t **startpos)
00174 {
00175 int namelen = strlen(name);
00176 const char *curname;
00177
00178 spinlock_lock(&cmd_lock);
00179
00180 if (!*startpos)
00181 *startpos = cmd_head.next;
00182
00183 for (;*startpos != &cmd_head;*startpos = (*startpos)->next) {
00184 cmd_info_t *hlp;
00185 hlp = list_get_instance(*startpos, cmd_info_t, link);
00186
00187 curname = hlp->name;
00188 if (strlen(curname) < namelen)
00189 continue;
00190 if (strncmp(curname, name, namelen) == 0) {
00191 spinlock_unlock(&cmd_lock);
00192 return curname+namelen;
00193 }
00194 }
00195 spinlock_unlock(&cmd_lock);
00196 return NULL;
00197 }
00198
00199
00205 static int cmdtab_compl(char *name)
00206 {
00207 char output[MAX_SYMBOL_NAME+1];
00208 link_t *startpos = NULL;
00209 const char *foundtxt;
00210 int found = 0;
00211 int i;
00212
00213 output[0] = '\0';
00214 while ((foundtxt = cmdtab_search_one(name, &startpos))) {
00215 startpos = startpos->next;
00216 if (!found)
00217 strncpy(output, foundtxt, strlen(foundtxt)+1);
00218 else {
00219 for (i=0; output[i] && foundtxt[i] && output[i]==foundtxt[i]; i++)
00220 ;
00221 output[i] = '\0';
00222 }
00223 found++;
00224 }
00225 if (!found)
00226 return 0;
00227
00228 if (found > 1 && !strlen(output)) {
00229 printf("\n");
00230 startpos = NULL;
00231 while ((foundtxt = cmdtab_search_one(name, &startpos))) {
00232 cmd_info_t *hlp;
00233 hlp = list_get_instance(startpos, cmd_info_t, link);
00234 printf("%s - %s\n", hlp->name, hlp->description);
00235 startpos = startpos->next;
00236 }
00237 }
00238 strncpy(name, output, MAX_SYMBOL_NAME);
00239 return found;
00240
00241 }
00242
00243 static char * clever_readline(const char *prompt, chardev_t *input)
00244 {
00245 static int histposition = 0;
00246
00247 char tmp[MAX_CMDLINE+1];
00248 int curlen = 0, position = 0;
00249 char *current = history[histposition];
00250 int i;
00251 char mod;
00252 char c;
00253
00254 printf("%s> ", prompt);
00255 while (1) {
00256 c = _getc(input);
00257 if (c == '\n') {
00258 putchar(c);
00259 break;
00260 } if (c == '\b') {
00261 if (position == 0)
00262 continue;
00263 for (i=position; i<curlen;i++)
00264 current[i-1] = current[i];
00265 curlen--;
00266 position--;
00267 putchar('\b');
00268 for (i=position;i<curlen;i++)
00269 putchar(current[i]);
00270 putchar(' ');
00271 rdln_print_c('\b',curlen-position+1);
00272 continue;
00273 }
00274 if (c == '\t') {
00275 int found;
00276
00277
00278 for (;position<curlen && current[position]!=' ';position++)
00279 putchar(current[position]);
00280
00281 for (i=position-1;i >= 0 && current[i]!=' ' ;i--)
00282 ;
00283
00284 if (tmp[0] == '*' || tmp[0] == '&')
00285 for (i=1;tmp[i];i++)
00286 tmp[i-1] = tmp[i];
00287 i++;
00288 strncpy(tmp, current+i, position-i+1);
00289
00290 if (i==0) {
00291 found = cmdtab_compl(tmp);
00292 } else {
00293 found = symtab_compl(tmp);
00294 }
00295
00296 if (found == 0)
00297 continue;
00298 for (i=0;tmp[i] && curlen < MAX_CMDLINE;i++,curlen++)
00299 insert_char(current, tmp[i], i+position);
00300
00301 if (strlen(tmp) || found==1) {
00302 for (i=position;i<curlen;i++)
00303 putchar(current[i]);
00304 position += strlen(tmp);
00305
00306 if (found == 1 && position == curlen && \
00307 curlen < MAX_CMDLINE) {
00308 current[position] = ' ';
00309 curlen++;
00310 position++;
00311 putchar(' ');
00312 }
00313 } else {
00314 printf("%s> ", prompt);
00315 for (i=0; i<curlen;i++)
00316 putchar(current[i]);
00317 position += strlen(tmp);
00318 }
00319 rdln_print_c('\b', curlen-position);
00320 continue;
00321 }
00322 if (c == 0x1b) {
00323 mod = _getc(input);
00324 c = _getc(input);
00325
00326 if (mod != 0x5b && mod != 0x4f)
00327 continue;
00328
00329 if (c == 0x33 && _getc(input) == 0x7e) {
00330
00331 if (position == curlen)
00332 continue;
00333 for (i=position+1; i<curlen;i++) {
00334 putchar(current[i]);
00335 current[i-1] = current[i];
00336 }
00337 putchar(' ');
00338 rdln_print_c('\b',curlen-position);
00339 curlen--;
00340 }
00341 else if (c == 0x48) {
00342 rdln_print_c('\b',position);
00343 position = 0;
00344 }
00345 else if (c == 0x46) {
00346 for (i=position;i<curlen;i++)
00347 putchar(current[i]);
00348 position = curlen;
00349 }
00350 else if (c == 0x44) {
00351 if (position > 0) {
00352 putchar('\b');
00353 position--;
00354 }
00355 continue;
00356 }
00357 else if (c == 0x43) {
00358 if (position < curlen) {
00359 putchar(current[position]);
00360 position++;
00361 }
00362 continue;
00363 }
00364 else if (c == 0x41 || c == 0x42) {
00365
00366 rdln_print_c('\b',position);
00367 rdln_print_c(' ',curlen);
00368 rdln_print_c('\b',curlen);
00369 if (c == 0x41)
00370 histposition--;
00371 else
00372 histposition++;
00373 if (histposition < 0)
00374 histposition = KCONSOLE_HISTORY -1 ;
00375 else
00376 histposition = histposition % KCONSOLE_HISTORY;
00377 current = history[histposition];
00378 printf("%s", current);
00379 curlen = strlen(current);
00380 position = curlen;
00381 continue;
00382 }
00383 continue;
00384 }
00385 if (curlen >= MAX_CMDLINE)
00386 continue;
00387
00388 insert_char(current, c, position);
00389
00390 curlen++;
00391 for (i=position;i<curlen;i++)
00392 putchar(current[i]);
00393 position++;
00394 rdln_print_c('\b',curlen-position);
00395 }
00396 if (curlen) {
00397 histposition++;
00398 histposition = histposition % KCONSOLE_HISTORY;
00399 }
00400 current[curlen] = '\0';
00401 return current;
00402 }
00403
00408 void kconsole(void *prompt)
00409 {
00410 cmd_info_t *cmd_info;
00411 count_t len;
00412 char *cmdline;
00413
00414 if (!stdin) {
00415 printf("%s: no stdin\n", __FUNCTION__);
00416 return;
00417 }
00418
00419 while (true) {
00420 cmdline = clever_readline(prompt, stdin);
00421 len = strlen(cmdline);
00422 if (!len)
00423 continue;
00424 cmd_info = parse_cmdline(cmdline, len);
00425 if (!cmd_info)
00426 continue;
00427 if (strncmp(cmd_info->name,"exit", \
00428 min(strlen(cmd_info->name),5)) == 0)
00429 break;
00430 (void) cmd_info->func(cmd_info->argv);
00431 }
00432 }
00433
00434 static int parse_int_arg(char *text, size_t len, __native *result)
00435 {
00436 char symname[MAX_SYMBOL_NAME];
00437 __address symaddr;
00438 bool isaddr = false;
00439 bool isptr = false;
00440
00441
00442 if (text[0] == '&') {
00443 isaddr = true;
00444 text++;len--;
00445 } else if (text[0] == '*') {
00446 isptr = true;
00447 text++;len--;
00448 }
00449 if (text[0] < '0' || text[0] > '9') {
00450 strncpy(symname, text, min(len+1, MAX_SYMBOL_NAME));
00451 symaddr = get_symbol_addr(symname);
00452 if (!symaddr) {
00453 printf("Symbol %s not found.\n",symname);
00454 return -1;
00455 }
00456 if (symaddr == (__address) -1) {
00457 printf("Duplicate symbol %s.\n",symname);
00458 symtab_print_search(symname);
00459 return -1;
00460 }
00461 if (isaddr)
00462 *result = (__native)symaddr;
00463 else if (isptr)
00464 *result = **((__native **)symaddr);
00465 else
00466 *result = *((__native *)symaddr);
00467 } else {
00468 *result = atoi(text);
00469 if (isptr)
00470 *result = *((__native *)*result);
00471 }
00472
00473 return 0;
00474 }
00475
00483 cmd_info_t *parse_cmdline(char *cmdline, size_t len)
00484 {
00485 index_t start = 0, end = 0;
00486 cmd_info_t *cmd = NULL;
00487 link_t *cur;
00488 int i;
00489 int error = 0;
00490
00491 if (!parse_argument(cmdline, len, &start, &end)) {
00492
00493 return NULL;
00494 }
00495
00496 spinlock_lock(&cmd_lock);
00497
00498 for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
00499 cmd_info_t *hlp;
00500
00501 hlp = list_get_instance(cur, cmd_info_t, link);
00502 spinlock_lock(&hlp->lock);
00503
00504 if (strncmp(hlp->name, &cmdline[start], max(strlen(hlp->name),
00505 end-start+1)) == 0) {
00506 cmd = hlp;
00507 break;
00508 }
00509
00510 spinlock_unlock(&hlp->lock);
00511 }
00512
00513 spinlock_unlock(&cmd_lock);
00514
00515 if (!cmd) {
00516
00517 printf("Unknown command.\n");
00518 return NULL;
00519 }
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530 for (i = 0; i < cmd->argc; i++) {
00531 char *buf;
00532 start = end + 1;
00533 if (!parse_argument(cmdline, len, &start, &end)) {
00534 printf("Too few arguments.\n");
00535 spinlock_unlock(&cmd->lock);
00536 return NULL;
00537 }
00538
00539 error = 0;
00540 switch (cmd->argv[i].type) {
00541 case ARG_TYPE_STRING:
00542 buf = cmd->argv[i].buffer;
00543 strncpy(buf, (const char *) &cmdline[start], min((end - start) + 2, cmd->argv[i].len));
00544 buf[min((end - start) + 1, cmd->argv[i].len - 1)] = '\0';
00545 break;
00546 case ARG_TYPE_INT:
00547 if (parse_int_arg(cmdline+start, end-start+1,
00548 &cmd->argv[i].intval))
00549 error = 1;
00550 break;
00551 case ARG_TYPE_VAR:
00552 if (start != end && cmdline[start] == '"' && cmdline[end] == '"') {
00553 buf = cmd->argv[i].buffer;
00554 strncpy(buf, (const char *) &cmdline[start+1],
00555 min((end-start), cmd->argv[i].len));
00556 buf[min((end - start), cmd->argv[i].len - 1)] = '\0';
00557 cmd->argv[i].intval = (__native) buf;
00558 cmd->argv[i].vartype = ARG_TYPE_STRING;
00559 } else if (!parse_int_arg(cmdline+start, end-start+1,
00560 &cmd->argv[i].intval))
00561 cmd->argv[i].vartype = ARG_TYPE_INT;
00562 else {
00563 printf("Unrecognized variable argument.\n");
00564 error = 1;
00565 }
00566 break;
00567 case ARG_TYPE_INVALID:
00568 default:
00569 printf("invalid argument type\n");
00570 error = 1;
00571 break;
00572 }
00573 }
00574
00575 if (error) {
00576 spinlock_unlock(&cmd->lock);
00577 return NULL;
00578 }
00579
00580 start = end + 1;
00581 if (parse_argument(cmdline, len, &start, &end)) {
00582 printf("Too many arguments.\n");
00583 spinlock_unlock(&cmd->lock);
00584 return NULL;
00585 }
00586
00587 spinlock_unlock(&cmd->lock);
00588 return cmd;
00589 }
00590
00605 bool parse_argument(char *cmdline, size_t len, index_t *start, index_t *end)
00606 {
00607 int i;
00608 bool found_start = false;
00609
00610 ASSERT(start != NULL);
00611 ASSERT(end != NULL);
00612
00613 for (i = *start; i < len; i++) {
00614 if (!found_start) {
00615 if (is_white(cmdline[i]))
00616 (*start)++;
00617 else
00618 found_start = true;
00619 } else {
00620 if (is_white(cmdline[i]))
00621 break;
00622 }
00623 }
00624 *end = i - 1;
00625
00626 return found_start;
00627 }
00628