1/*******************************************************************************
2**+--------------------------------------------------------------------------+**
3**|                                                                          |**
4**| Copyright 1998-2008 Texas Instruments, Inc. - http://www.ti.com/         |**
5**|                                                                          |**
6**| Licensed under the Apache License, Version 2.0 (the "License");          |**
7**| you may not use this file except in compliance with the License.         |**
8**| You may obtain a copy of the License at                                  |**
9**|                                                                          |**
10**|     http://www.apache.org/licenses/LICENSE-2.0                           |**
11**|                                                                          |**
12**| Unless required by applicable law or agreed to in writing, software      |**
13**| distributed under the License is distributed on an "AS IS" BASIS,        |**
14**| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |**
15**| See the License for the specific language governing permissions and      |**
16**| limitations under the License.                                           |**
17**|                                                                          |**
18**+--------------------------------------------------------------------------+**
19*******************************************************************************/
20
21#ifndef _WINDOWS
22	#include <sys/select.h>
23	#include <unistd.h>
24	#include <signal.h>
25
26	#include "ipc.h"
27	#include "g_tester.h"
28	#include "wipp_ctrl.h"
29#endif /* __LINUX__ */
30
31#ifdef _WINDOWS
32#else
33	#include <errno.h>
34#endif
35
36#include <string.h>
37#include <stdlib.h>
38#include <stdio.h>
39#include <ctype.h>
40
41
42#include "ticon.h"
43#include "console.h"
44#include "cu_cmd.h"
45
46static ConEntry_t *p_mon_root;
47static ConEntry_t *p_cur_dir;
48static char       *p_inbuf;
49static volatile int stop_UI_Monitor;
50
51#define INBUF_LENGTH          1024
52/*#define PRINT_LEN_PER_PARM    40*/
53#define ROOT_NAME             "/"
54
55/* Internal functions */
56static void        console_allocRoot( void );
57static void        console_displayDir( ConEntry_t *p_dir );
58static t_TokenType console_getWord( char *name, U16 len );
59static t_TokenType console_getStrParam( char *buf, ConParm_t *param );
60static t_TokenType console_analizeToken( char *name );
61static U16         console_getNParms( ConEntry_t *p_token );
62static int         console_parseParms( ConEntry_t *p_token, U16 *pnParms );
63static ConEntry_t *console_searchToken( ConEntry_t *p_dir, char *name );
64static void        console_dirHelp( void );
65static void        console_displayHelp( ConEntry_t *p_token );
66static int         console_chooseAlias( ConEntry_t *p_dir, ConEntry_t *p_new_token );
67
68
69/***************************************************************
70
71   Function : consoleRunScript
72
73   Description: Execute command from file
74
75   Parameters: script_file - name of script file
76
77   Output:  !NULL - if 'quit' command was executed
78***************************************************************/
79int consoleRunScript( char *script_file )
80{
81    FILE *hfile = fopen(script_file, "r" );
82
83    if( hfile )
84    {
85        char buf[INBUF_LENGTH];
86        stop_UI_Monitor = FALSE;
87
88        while( fgets(buf, sizeof(buf), hfile ) )
89        {
90            console_printf_terminal("script <%s>\n", script_file);
91            console_ParseString( buf );
92            if( stop_UI_Monitor )
93                break;
94        }
95
96        fclose(hfile);
97    }
98    else
99        perror( script_file );
100
101    return stop_UI_Monitor;
102}
103
104
105/***************************************************************
106
107   Function : consoleAddDirExt
108
109   Description: Add subdirectory
110
111   Parameters: p_root - root directory handle (might be NULL)
112               name   - directory name
113
114   Output:  the new created directory handle
115            =NULL - failure
116***************************************************************/
117handle_t consoleAddDirExt(
118                       handle_t   hRoot,          /* Upper directory handle. NULL=root */
119                       const char *name,          /* New directory name */
120                       const char *desc )         /* Optional dir description */
121{
122    ConEntry_t *p_root = (ConEntry_t *)hRoot;
123    ConEntry_t *p_dir;
124    ConEntry_t **p_e;
125
126    if (!p_mon_root)
127        console_allocRoot( );
128
129    if (!p_root)
130        p_root = p_mon_root;
131
132    ASSERT( p_root && (p_root->sel == Dir) );
133
134    if ( (p_dir=(ConEntry_t *)malloc( sizeof( ConEntry_t )) ) == NULL)
135        return NULL;
136
137    memset( p_dir, 0, sizeof( ConEntry_t ) );
138    strncpy( p_dir->name, name, MAX_NAME_LEN );
139    strncpy( p_dir->help, desc, MAX_HELP_LEN );
140    p_dir->sel = Dir;
141
142    console_chooseAlias( p_root, p_dir );
143
144    /* Add new directory to the root's list */
145    p_dir->u.dir.upper = p_root;
146    p_e = &(p_root->u.dir.first);
147    while (*p_e)
148        p_e = &((*p_e)->next);
149    *p_e = p_dir;
150
151    return p_dir;
152}
153
154/***************************************************************
155
156   Function : consoleAddToken
157
158   Description: Add token
159
160   Parameters: p_dir  - directory handle (might be NULL=root)
161               name   - token name
162               help   - help string
163               p_func - token handler
164               p_parms- array of parameter descriptions.
165                        Must be terminated with {0}.
166                        Each parm descriptor is a struct
167                        { "myname",         - name
168                          10,               - low value
169                          20,               - high value
170                          0 }               - default value =-1 no default
171                                              or address for string parameter
172
173   Output:  E_OK - OK
174            !=0 - error
175***************************************************************/
176consoleErr consoleAddToken( handle_t      hDir,
177                      const char    *name,
178                      const char    *help,
179                      FuncToken_t   p_func,
180                      ConParm_t     p_parms[] )
181{
182   ConEntry_t *p_dir = (ConEntry_t *)hDir;
183   ConEntry_t *p_token;
184   ConEntry_t **p_e;
185   U16       i;
186
187   if (!p_mon_root)
188      console_allocRoot( );
189
190   if (!p_dir)
191      p_dir = p_mon_root;
192
193   ASSERT( p_dir && (p_dir->sel == Dir) );
194
195   /* Initialize token structure */
196   if ((p_token=(ConEntry_t *)calloc( 1, sizeof(ConEntry_t) )) == NULL)
197   {
198      fprintf(stderr, "** no memory **\n");
199      return E_NOMEMORY;
200   }
201
202
203   /* Copy name */
204   strncpy( p_token->name, name, MAX_NAME_LEN );
205   strncpy( p_token->help, help, MAX_HELP_LEN );
206   p_token->sel = Token;
207   p_token->u.token.f_tokenFunc = p_func;
208
209   /* Convert name to lower case and choose alias */
210   console_chooseAlias( p_dir, p_token );
211
212   /* Copy parameters */
213   if ( p_parms )
214   {
215      for(i = 0; p_parms->name && p_parms->name[0] && ( i < MAX_NUM_OF_PARMS); i++ )
216      {
217         ConParm_t *p_token_parm = &p_token->u.token.parm[i];
218
219         /* String parameter must have an address */
220         if(p_parms->flags & (CON_PARM_STRING | CON_PARM_LINE))
221         {
222            if ( p_parms->hi_val >= INBUF_LENGTH )
223         {
224                fprintf(stderr, "** buffer too big: %s/%s\n", p_dir->name, name);
225            free( p_token );
226                return E_NOMEMORY;
227
228            }
229            if (p_parms->hi_val == 0 || (p_parms->flags & CON_PARM_RANGE) )
230            {
231            fprintf(stderr, "** Bad string param definition: %s/%s\n", p_dir->name, name );
232                free( p_token );
233            return E_BADPARM;
234         }
235
236            p_parms->value = (U32) calloc(1, p_parms->hi_val+1);
237            if( !p_parms->value )
238            {
239                fprintf(stderr, "** No memory: %s/%s (max.size=%ld)\n", p_dir->name, name, p_parms->hi_val );
240                free( p_token );
241                return E_NOMEMORY;
242            }
243        }
244
245         /* Copy parameter */
246         *p_token_parm = *p_parms;
247         if( p_token_parm->hi_val || p_token_parm->low_val )
248             p_token_parm->flags |= CON_PARM_RANGE;
249         p_token_parm->name = (const char *)p_token->u.token.name[i];
250         strncpy( p_token->u.token.name[i], p_parms->name, MAX_NAME_LEN );
251         ++p_parms;
252      }
253      if ((i == MAX_NUM_OF_PARMS) && p_parms->name[0])
254      {
255            fprintf(stderr, "** Too many params: %s/%s\n", p_dir->name, name );
256         free( p_token );
257         return E_TOOMANY;
258      }
259   }
260
261   /* Add token to the directory */
262   p_e = &(p_dir->u.dir.first);
263   while (*p_e)
264      p_e = &((*p_e)->next);
265   *p_e = p_token;
266
267   return E_OK;
268}
269
270
271/* Monitor driver */
272void consoleStart( void )
273{
274#ifndef _WINDOWS
275   fd_set read_set;
276   int max_fd_index;
277   int result;
278   int pid;
279#endif /* __LINUX__ */
280
281   char inbuf[INBUF_LENGTH];
282
283   if (!p_mon_root)
284      return;
285
286   stop_UI_Monitor = FALSE;
287   console_displayDir( p_cur_dir );
288
289   while(!stop_UI_Monitor)
290   {
291
292#ifndef _WINDOWS
293	   /***********************************************************************************/
294       /* Wait for one of two external events: 											 */
295       /* -----------------------------------											*/
296       /*																			   */
297       /* 1. Data received from STDIN												  */
298       /* 2. Data received from one of the TCP clients							 	 */
299	   /* 3. Data received from iperf process stdout (if enabled)					*/
300	   /****************************************************************************/
301
302	   /* Prepare the read set fields */
303	   FD_ZERO(&read_set);
304	   FD_SET(0, &read_set);
305	   FD_SET(ipc_pipe[0], &read_set);
306	   FD_SET(wipp_control_general_process_out_pipe[0], &read_set);
307
308	   /* Determine the maximum index of the file descriptor */
309	   max_fd_index = (max(wipp_control_general_process_out_pipe[0], max(0, ipc_pipe[0])) + 1);
310
311	   /* Wait for event - blocking */
312	   result = select(max_fd_index, &read_set, NULL, NULL, NULL);
313
314	   if (result > 0)
315	   {
316		   if (FD_ISSET(0, &read_set))
317		   {
318			   /*****************************/
319			   /* Data received from STDIN */
320			   /***************************/
321
322                if ( fgets( inbuf, sizeof(inbuf), stdin ) <= 0 )
323				 return;
324
325				console_ParseString( inbuf );
326
327		   }
328
329		   if (FD_ISSET(ipc_pipe[0], &read_set))
330		   {
331			   /**********************************/
332			   /* Data received from TCP client */
333			   /********************************/
334
335			   result = read(ipc_pipe[0], (U8 *)inbuf, (U16)sizeof(inbuf));
336
337			   /* Get the pid of the calling process */
338			   pid = *(inbuf + 0) | (*(inbuf + 1) << 8);
339
340			   /* Signal the calling process (tell him that we have
341			      received the command, and he can send us another one */
342			   if (pid != 0xFFFF)
343			   {
344				   kill(pid, SIGUSR1);
345			   }
346
347			   if (result > 0)
348			   {
349				   console_ParseString(inbuf + 2);
350			   }
351		   }
352
353		   if (FD_ISSET(wipp_control_general_process_out_pipe[0], &read_set))
354		   {
355			   /*****************************************/
356			   /* Data received general process stdout */
357			   /***************************************/
358
359			   result = read(wipp_control_general_process_out_pipe[0], (U8 *)inbuf + 3, sizeof(inbuf) - 3);
360
361			   if (result > 0)
362			   {
363				   wipp_control_send_iperf_results_to_host(WIPP_CONTROL_EVT_RUN_PROCESS_STDOUT, inbuf, result);
364			   }
365		   }
366	   }
367	   else
368	   {
369		   /* Error */
370		   console_printf_terminal("Input selection mismatch...\n");
371
372		   return;
373	   }
374
375#else  /* __LINUX__ */
376#endif /* __LINUX__ */
377   }
378}
379
380
381/* Parse the given input string and exit.
382   All commands in the input string are executed one by one.
383*/
384void console_ParseString(char *input_string )
385{
386   ConEntry_t  *p_token;
387   char        name[MAX_NAME_LEN];
388   t_TokenType tType;
389   U16        nParms;
390
391
392#ifndef _WINDOWS
393	/* Check if this is WIPP control command, if it is - process it */
394	if (wipp_control_check_command(input_string))
395	{
396		return;
397	}
398
399	/* Check if this is g_tester control command, if it is - process it */
400	if (g_tester_check_command((unsigned char*) input_string))
401	{
402		return;
403	}
404#endif /* __LINUX__ */
405
406   if (!p_mon_root)
407      return;
408
409   if( input_string[strlen(input_string)-1] == '\n' )
410   {
411      char *s = (char *) &input_string[strlen(input_string)-1];
412  	  *s = 0;
413   }
414   p_inbuf = (char *)input_string;
415   stop_UI_Monitor = FALSE;
416
417   /* Interpret empty string as "display directory" */
418   if ( p_inbuf && !*p_inbuf )
419      console_displayDir( p_cur_dir );
420
421   while(!stop_UI_Monitor && p_inbuf && *p_inbuf)
422   {
423      tType = console_getWord( name, MAX_NAME_LEN );
424      switch( tType )
425      {
426
427      case NameToken:
428         p_token = console_searchToken( p_cur_dir, name );
429         if (p_token == NULL)
430         {
431            fprintf( stderr, "**Error: '%s'**\n", name);
432            p_inbuf = NULL;
433         }
434         else if (p_token->sel == Dir)
435         {
436            p_cur_dir = p_token;
437            console_displayDir( p_cur_dir );
438         }
439         else
440         {  /* Function token */
441            if (!console_parseParms( p_token, &nParms ))
442               console_displayHelp( p_token );
443            else
444               p_token->u.token.f_tokenFunc( p_token->u.token.parm, nParms );
445         }
446         break;
447
448      case UpToken: /* Go to upper directory */
449         if (p_cur_dir->u.dir.upper)
450            p_cur_dir = p_cur_dir->u.dir.upper;
451         console_displayDir( p_cur_dir );
452         break;
453
454      case RootToken: /* Go to the root directory */
455         if (p_cur_dir->u.dir.upper)
456            p_cur_dir = p_mon_root;
457         console_displayDir( p_cur_dir );
458         break;
459
460      case HelpToken: /* Display help */
461         if (( console_getWord( name, MAX_NAME_LEN ) == NameToken ) &&
462             ((p_token = console_searchToken( p_cur_dir, name )) != NULL ) &&
463             (p_token->sel == Token) )
464            console_displayHelp( p_token );
465         else
466            console_dirHelp( );
467         break;
468
469      case DirHelpToken:
470         console_displayDir( p_cur_dir );
471			console_printf_terminal("Type ? <name> for command help, \"/\"-root, \"..\"-upper\n" );
472         break;
473
474      case BreakToken: /* Clear buffer */
475         p_inbuf = NULL;
476         break;
477
478      case EmptyToken:
479         break;
480
481      }
482   }
483}
484
485
486/* Stop monitor driver */
487void consoleStop( void )
488{
489   stop_UI_Monitor = TRUE;
490}
491
492
493/*********************************************************/
494/* Internal functions                                    */
495/*********************************************************/
496
497/* Allocate root directory */
498void console_allocRoot( void )
499{
500   /* The very first call. Allocate root structure */
501   if ((p_mon_root=(ConEntry_t *)calloc( 1, sizeof( ConEntry_t ) ) ) == NULL)
502   {
503      ASSERT( p_mon_root );
504      return;
505   }
506   strcpy( p_mon_root->name, ROOT_NAME );
507   p_mon_root->sel = Dir;
508   p_cur_dir = p_mon_root;
509}
510
511/* Display directory */
512void console_displayDir( ConEntry_t *p_dir )
513{
514   char out_buf[512];
515   ConEntry_t *p_token;
516
517   sprintf( out_buf, "%s%s> ", (p_dir==p_mon_root)? "" : ".../", p_dir->name );
518   p_token = p_dir->u.dir.first;
519   while( p_token )
520   {
521      if( (strlen(out_buf) + strlen(p_token->name) + 2)>= sizeof(out_buf) )
522      {
523          fprintf(stderr, "** console_displayDir(): buffer too small....\n");
524          break;
525      }
526      strcat( out_buf, p_token->name );
527      if ( p_token->sel == Dir )
528         strcat( out_buf, "/" );
529      p_token = p_token->next;
530      if (p_token)
531         strcat( out_buf, ", " );
532   }
533   console_printf_terminal("%s\n", out_buf );
534}
535
536
537/* Cut the first U16 from <p_inbuf>.
538   Return the U16 in <name> and updated <p_inbuf>
539*/
540static t_TokenType console_getWord( char *name, U16 len )
541{
542   U16        i=0;
543   t_TokenType tType;
544
545
546   p_inbuf = console_ltrim(p_inbuf);
547
548   while( *p_inbuf && *p_inbuf!=' ' && i<len )
549      name[i++] = *(p_inbuf++);
550
551   if (i<len)
552      name[i] = 0;
553
554   tType   = console_analizeToken( name );
555
556   return tType;
557}
558
559static t_TokenType console_getStrParam( char *buf, ConParm_t *param )
560{
561    t_TokenType tType;
562    U32         i, len = param->hi_val;
563    char        *end_buf;
564
565    p_inbuf = console_ltrim(p_inbuf);
566
567    if( param->flags & CON_PARM_LINE )
568    {
569        strcpy(buf, p_inbuf );
570        p_inbuf += strlen(p_inbuf);
571    }
572    else
573    {
574        if( *p_inbuf == '\"' )
575        {
576            end_buf = strchr(p_inbuf+1, '\"' );
577            if( !end_buf )
578            {
579                fprintf(stderr, "** invalid string param: '%s'\n", p_inbuf );
580                p_inbuf += strlen(p_inbuf);
581                return EmptyToken;
582            }
583            if( (end_buf - p_inbuf - 1) > (int)len )
584            {
585                fprintf(stderr, "** param is too long: '%s'\n", p_inbuf );
586                p_inbuf += strlen(p_inbuf);
587                return EmptyToken;
588            }
589            *end_buf = 0;
590            strcpy( buf, p_inbuf+1 );
591            p_inbuf = end_buf + 1;
592        }
593        else
594        {
595            for( i=0; *p_inbuf && *p_inbuf!=' ' && i<len; i++ )
596                buf[i] = *(p_inbuf++);
597
598            buf[i] = 0;
599            if( *p_inbuf && *p_inbuf != ' ' )
600            {
601                fprintf(stderr, "** param is too long: '%s'\n", p_inbuf-strlen(buf) );
602                p_inbuf += strlen(p_inbuf);
603                return EmptyToken;
604            }
605        }
606    }
607
608    tType   = console_analizeToken( buf );
609
610    return tType;
611}
612
613/* Make a preliminary analizis of <name> token.
614   Returns a token type (Empty, Up, Root, Break, Name)
615*/
616t_TokenType console_analizeToken( char *name )
617{
618   if (!name[0])
619      return EmptyToken;
620
621   if (!strcmp( name, TOKEN_UP ) )
622      return UpToken;
623
624   if (!strcmp( name, TOKEN_ROOT ) )
625      return RootToken;
626
627   if (!strcmp( name, TOKEN_BREAK ) )
628      return BreakToken;
629
630   if (!strcmp( name, TOKEN_HELP ) )
631      return HelpToken;
632
633   if (!strcmp( name, TOKEN_DIRHELP ) )
634      return DirHelpToken;
635
636   return NameToken;
637
638}
639
640
641/* Returns number of parameters of the given token
642*/
643static U16 console_getNParms( ConEntry_t *p_token )
644{
645   U16 i;
646   if ( !p_token->u.token.parm )
647      return 0;
648   for( i=0;
649        (i<MAX_NUM_OF_PARMS-1) &&
650         p_token->u.token.parm[i].name &&
651         p_token->u.token.parm[i].name[0];
652        i++ )
653      ;
654   return i;
655}
656
657/* Parse p_inbuf string based on parameter descriptions in <p_token>.
658   Fill parameter values in <p_token>.
659   Returns the number of parameters filled.
660   To Do: add a option of one-by-one user input of missing parameters.
661*/
662int console_parseParms( ConEntry_t *p_token, U16 *pnParms )
663{
664    U16 nTotalParms = console_getNParms( p_token );
665    U16 nParms=0;
666    char *end_buf = NULL, parm[INBUF_LENGTH];
667    U16 i, print_params = 0;
668    U32 val = 0;
669    S32 sval = 0;
670
671    /* Mark all parameters as don't having an explicit value */
672    for( i=0; i<nTotalParms; i++ )
673            p_token->u.token.parm[i].flags |= CON_PARM_NOVAL;
674
675    /*        -----------------              */
676    p_inbuf = console_ltrim(p_inbuf);
677    if( p_inbuf[0] == '!' && p_inbuf[1] == '!' )
678    {
679        p_inbuf += 2; print_params = 1;
680    }
681    /*        -----------------              */
682
683    /* Build a format string */
684    for( i=0; i<nTotalParms; i++ )
685    {
686        if (p_token->u.token.parm[i].flags & (CON_PARM_STRING | CON_PARM_LINE) )
687        {
688            /* For a string parameter value is the string address */
689            /* and hi_val is the string length                   */
690            if (console_getStrParam( parm, &p_token->u.token.parm[i] ) != NameToken)
691                break;
692            if( strlen(parm) > p_token->u.token.parm[i].hi_val ||
693                (p_token->u.token.parm[i].low_val && p_token->u.token.parm[i].low_val > strlen(parm) ) )
694        {
695                fprintf(stderr, "param '%s' must be %ld..%ld chars\n", p_token->u.token.parm[i].name,
696                        p_token->u.token.parm[i].low_val, p_token->u.token.parm[i].hi_val);
697                return FALSE;
698
699            }
700            strcpy( (char *)p_token->u.token.parm[i].value, parm );
701        }
702        else
703        {
704            if (console_getWord( parm, MAX_PARM_LEN ) != NameToken)
705                break;
706
707            if (p_token->u.token.parm[i].flags & CON_PARM_SIGN)
708                sval = strtol( parm, &end_buf, 0 );
709            else
710                val = strtoul( parm, &end_buf, 0 );
711            if( /*errno || */end_buf <= parm )
712                    break;
713
714/*             if (sscanf( parm, "%i", &val ) != 1)*/
715/*                 break;*/
716
717            /* Check value */
718            if (p_token->u.token.parm[i].flags & CON_PARM_RANGE)
719            {
720                if (p_token->u.token.parm[i].flags & CON_PARM_SIGN)
721                {
722                    if ((sval < (S32)p_token->u.token.parm[i].low_val) ||
723                        (sval > (S32)p_token->u.token.parm[i].hi_val) )
724                    {
725                        fprintf( stderr, "%s: %d out of range (%d, %d)\n",
726                            p_token->u.token.parm[i].name, (int)sval,
727                            (int)p_token->u.token.parm[i].low_val, (int)p_token->u.token.parm[i].hi_val );
728                        return FALSE;
729                    }
730
731                }
732                else
733                {
734                    if ((val < p_token->u.token.parm[i].low_val) ||
735                        (val > p_token->u.token.parm[i].hi_val) )
736                    {
737                        fprintf( stderr, "%s: %ld out of range (%ld, %ld)\n",
738                            p_token->u.token.parm[i].name, val,
739                            p_token->u.token.parm[i].low_val, p_token->u.token.parm[i].hi_val );
740                        return FALSE;
741                    }
742                }
743            }
744
745            if (p_token->u.token.parm[i].flags & CON_PARM_SIGN)
746                p_token->u.token.parm[i].value = sval;
747            else
748                p_token->u.token.parm[i].value = val;
749        }
750
751        p_token->u.token.parm[i].flags &= ~CON_PARM_NOVAL;
752        ++nParms;
753    }
754
755    /* Process default values */
756    for( ; i<nTotalParms; i++ )
757    {
758        if ((p_token->u.token.parm[i].flags & CON_PARM_DEFVAL) != 0)
759        {
760            p_token->u.token.parm[i].flags &= ~CON_PARM_NOVAL;
761            ++nParms;
762        }
763        else if (!(p_token->u.token.parm[i].flags & CON_PARM_OPTIONAL) )
764        {
765            /* Mandatory parameter missing */
766            return FALSE;
767        }
768    }
769
770    if( print_params )
771    {
772        printf("Params: %d\n", nParms );
773        for (i=0; i<nParms; i++ )
774        {
775            console_printf_terminal("%d: %s - flags:%d",
776                i+1, p_token->u.token.parm[i].name,
777                p_token->u.token.parm[i].flags);
778
779            if (p_token->u.token.parm[i].flags & CON_PARM_SIGN)
780                console_printf_terminal("min:%d, max:%d, value:%d ",p_token->u.token.parm[i].low_val, p_token->u.token.parm[i].hi_val,
781                    p_token->u.token.parm[i].value);
782            else
783                console_printf_terminal("min:%ld, max:%ld, value:%ld ",p_token->u.token.parm[i].low_val, p_token->u.token.parm[i].hi_val,
784                    p_token->u.token.parm[i].value);
785
786            console_printf_terminal("(%#lx)",p_token->u.token.parm[i].value );
787
788            if( p_token->u.token.parm[i].flags & (CON_PARM_LINE | CON_PARM_STRING ))
789            {
790                printf(" - '%s'", (char *) p_token->u.token.parm[i].value );
791            }
792            printf("\n");
793        }
794
795    }
796    *pnParms = nParms;
797
798    return TRUE;
799}
800
801/* Serach a token by name in the current directory */
802ConEntry_t *console_searchToken( ConEntry_t *p_dir, char *name )
803{
804   ConEntry_t *p_token;
805   U16        name_len = (U16)strlen( name );
806
807   /* Check alias */
808   p_token = p_dir->u.dir.first;
809   while( p_token )
810   {
811      if (p_token->alias &&
812          (name_len == ALIAS_LEN) &&
813          !console_stricmp( p_token->alias, name, ALIAS_LEN ) )
814          return p_token;
815      p_token = p_token->next;
816   }
817
818   /* Check name */
819   p_token = p_dir->u.dir.first;
820   while( p_token )
821   {
822      if (!console_stricmp( p_token->name, name, name_len ) )
823         break;
824      p_token = p_token->next;
825   }
826
827   return p_token;
828}
829
830
831/* Display help for each entry in the current directory */
832void  console_dirHelp( void )
833{
834   ConEntry_t *p_token;
835   char        print_str[80];
836
837   p_token = p_cur_dir->u.dir.first;
838
839   while( p_token )
840   {
841      if (p_token->sel == Dir)
842         sprintf( print_str, "%s: directory\n", p_token->name );
843      else
844         sprintf( print_str, "%s(%d parms): %s\n",
845                  p_token->name, console_getNParms(p_token), p_token->help );
846      console_printf_terminal( print_str );
847      p_token = p_token->next;
848   }
849
850   console_printf_terminal( "Type ? <name> for command help, \"/\"-root, \"..\"-upper\n" );
851}
852
853
854/* Display help a token */
855void  console_displayHelp( ConEntry_t *p_token )
856{
857   char bra, ket;
858   U16 nTotalParms = console_getNParms( p_token );
859   U16 i;
860
861
862   console_printf_terminal( "%s: %s ", p_token->help, p_token->name );
863   for( i=0; i<nTotalParms; i++ )
864   {
865      if (p_token->u.token.parm[i].flags & CON_PARM_OPTIONAL)
866      {
867         bra = '['; ket=']';
868      }
869      else
870      {
871         bra = '<'; ket='>';
872      }
873      console_printf_terminal( "%c%s", bra, p_token->u.token.parm[i].name );
874      if (p_token->u.token.parm[i].flags & CON_PARM_DEFVAL)
875      {
876          console_printf_terminal("=%lu", p_token->u.token.parm[i].value);
877      }
878      if (p_token->u.token.parm[i].flags & CON_PARM_RANGE)
879      {
880          console_printf_terminal( (p_token->u.token.parm[i].flags & CON_PARM_SIGN) ? " (%d..%d%s)" : " (%lu..%lu%s)",
881                  p_token->u.token.parm[i].low_val,
882                  p_token->u.token.parm[i].hi_val,
883                  (p_token->u.token.parm[i].flags & (CON_PARM_STRING | CON_PARM_LINE)) ? " chars" : "" );
884
885      }
886      console_printf_terminal( "%c \n",ket );
887   }
888}
889
890/* Choose unique alias for <name> in <p_dir> */
891/* Currently only single-character aliases are supported */
892int console_chooseAlias( ConEntry_t *p_dir, ConEntry_t *p_new_token )
893{
894   ConEntry_t *p_token;
895   int         i;
896   char        c;
897   char *new_alias = NULL;
898
899   /* find alias given from user */
900   for(i=0; p_new_token->name[i]; i++ )
901   {
902       if( isupper(p_new_token->name[i]) )
903       {
904           new_alias = &p_new_token->name[i];
905           break;
906       }
907   }
908
909   console_strlwr( p_new_token->name );
910
911   if( new_alias )
912   {
913      p_token = p_dir->u.dir.first;
914
915      while( p_token )
916      {
917         if (p_token->alias && (tolower( *p_token->alias ) == *new_alias) )
918         {
919/*            *new_alias = toupper(*new_alias);*/
920            fprintf( stderr, "**Error: duplicated alias '%c' in <%s> and <%s>**\n", *new_alias,
921                    p_token->name, p_new_token->name );
922            return 0;
923         }
924         p_token = p_token->next;
925      }
926      *new_alias = toupper(*new_alias);
927      p_new_token->alias = new_alias;
928      return 1;
929   }
930
931   i = 0;
932   while( p_new_token->name[i] )
933   {
934      c = p_new_token->name[i];
935      p_token = p_dir->u.dir.first;
936
937      while( p_token )
938      {
939         if (p_token->alias &&
940             (tolower( *p_token->alias ) == c) )
941            break;
942         p_token = p_token->next;
943      }
944      if (p_token)
945         ++i;
946      else
947      {
948         p_new_token->name[i] = toupper( c );
949         p_new_token->alias   = &p_new_token->name[i];
950         break;
951      }
952   }
953   return 1;
954}
955
956
957/* Convert string s to lower case. Return pointer to s */
958char  * console_strlwr( char *s )
959{
960   char  *s0=s;
961
962   while( *s )
963   {
964      *s = tolower( *s );
965      ++s;
966   }
967
968   return s0;
969}
970
971
972/* Compare strings case insensitive */
973int console_stricmp( char *s1, char *s2, U16 len )
974{
975   int  i;
976
977   for( i=0; i<len && s1[i] && s2[i]; i++ )
978   {
979      if (tolower( s1[i])  != tolower( s2[i] ))
980         break;
981   }
982
983   return ( (len - i) * (s1[i] - s2[i]) );
984}
985
986/* Remove leading blanks */
987char * console_ltrim(char *s )
988{
989    while( *s == ' ' || *s == '\t' ) s++;
990    return s;
991}
992
993#ifdef _WINDOWS
994#endif /* _WINDOWS*/
995
996
997