kconsole.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2005 Jakub Jermar
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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          * Make sure the command is not already listed.
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                         /* The command is already there. */
00119                         spinlock_unlock(&cmd_lock);
00120                         return 0;
00121                 }
00122 
00123                 /* Avoid deadlock. */
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                         /* The command is already there. */
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          * Now the command can be added.
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; /* Command Modifier */
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') { /* Backspace */
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') { /* Tabulator */
00275                         int found;
00276 
00277                         /* Move to the end of the word */
00278                         for (;position<curlen && current[position]!=' ';position++)
00279                                 putchar(current[position]);
00280                         /* Copy to tmp last word */
00281                         for (i=position-1;i >= 0 && current[i]!=' ' ;i--)
00282                                 ;
00283                         /* If word begins with * or &, skip it */
00284                         if (tmp[0] == '*' || tmp[0] == '&')
00285                                 for (i=1;tmp[i];i++)
00286                                         tmp[i-1] = tmp[i];
00287                         i++; /* I is at the start of the word */
00288                         strncpy(tmp, current+i, position-i+1);
00289 
00290                         if (i==0) { /* Command completion */
00291                                 found = cmdtab_compl(tmp);
00292                         } else { /* Symtab completion */
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) { /* If we have a hint */
00302                                 for (i=position;i<curlen;i++) 
00303                                         putchar(current[i]);
00304                                 position += strlen(tmp);
00305                                 /* Add space to end */
00306                                 if (found == 1 && position == curlen && \
00307                                     curlen < MAX_CMDLINE) {
00308                                         current[position] = ' ';
00309                                         curlen++;
00310                                         position++;
00311                                         putchar(' ');
00312                                 }
00313                         } else { /* No hint, table was printed */
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) { /* Special command */
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                                 /* Delete */
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) { /* Home */
00342                                 rdln_print_c('\b',position);
00343                                 position = 0;
00344                         } 
00345                         else if (c == 0x46) {  /* End */
00346                                 for (i=position;i<curlen;i++)
00347                                         putchar(current[i]);
00348                                 position = curlen;
00349                         }
00350                         else if (c == 0x44) { /* Left */
00351                                 if (position > 0) {
00352                                         putchar('\b');
00353                                         position--;
00354                                 }
00355                                 continue;
00356                         }
00357                         else if (c == 0x43) { /* Right */
00358                                 if (position < curlen) {
00359                                         putchar(current[position]);
00360                                         position++;
00361                                 }
00362                                 continue;
00363                         }
00364                         else if (c == 0x41 || c == 0x42) { 
00365                                 /* Up,down */
00366                                 rdln_print_c('\b',position);
00367                                 rdln_print_c(' ',curlen);
00368                                 rdln_print_c('\b',curlen);
00369                                 if (c == 0x41) /* Up */
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         /* If we get a name, try to find it in symbol table */
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 { /* It's a number - convert it */
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                 /* Command line did not contain alphanumeric word. */
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                 /* Unknown command. */
00517                 printf("Unknown command.\n");
00518                 return NULL;
00519         }
00520 
00521         /* cmd == hlp is locked */
00522         
00523         /*
00524          * The command line must be further analyzed and
00525          * the parameters therefrom must be matched and
00526          * converted to those specified in the cmd info
00527          * structure.
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 

Generated on Sun Jun 18 17:17:05 2006 for HelenOS Kernel (ppc32) by  doxygen 1.4.6