openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

variable.c (14629B)


      1  /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:	variable.c
      8  * Purpose:	Variable routines with scope support functions.
      9  */
     10 
     11 #include <sal/core/libc.h>
     12 #include <sal/appl/sal.h>
     13 #include <shared/bsl.h>
     14 #include <appl/diag/shell.h>
     15 #include <appl/diag/system.h>
     16 #include <appl/diag/parse.h>
     17 
     18 #define	VAR_IS_SYSTEM(_s) (*(_s) == PARSE_VARIABLE_SYSTEM)
     19 
     20 /*
     21  * Typedef:	var_t
     22  * Purpose:	Maps out a circular double linked list entry 
     23  *		representing a single variable.
     24  * Notes:	Each linked list contains a dummy entry at the
     25  *		head of the list for easy insert/delete.
     26  */
     27 typedef struct var_s {
     28     struct var_s	*v_next;	/* Next in linked list */
     29     struct var_s	*v_prev;	/* Next in linked list */
     30     char		*v_name;	/* Variable name */
     31     char		*v_value;	/* Variable value */
     32 } var_t;
     33 
     34 /*
     35  * Typedef:	var_scope_t
     36  * Purpose:	Defines a scope level for local variables. 
     37  */
     38 typedef struct var_scope_s {
     39     struct var_scope_s 	*vs_next;	/* Next in Queue */
     40     var_t		vs_local;	/* Local variable list */
     41 } var_scope_t;
     42 
     43 /*
     44  * Variable:	var_scope_list
     45  * Purpose:	Queue of pushed local variable lists, each queue
     46  *		entry contains a variable list. 
     47  */
     48     
     49 static	var_scope_t 	*var_scope_list = NULL;
     50 
     51 /*
     52  * Variable:	var_global_list
     53  * Purpose:	Global variable list.
     54  * Notes:	List is created with the dummy queue head.
     55  */
     56 static	var_t		var_global_list = 
     57    {&var_global_list, &var_global_list, NULL, NULL};
     58 
     59 #define	VAR_SYSTEM_STRING	\
     60     "\tSystem variables are those that begin with an \"_\". They may be\n\t"\
     61     "referenced but not set.  Use printenv to show the system variables.\n"
     62 
     63 void	*
     64 var_push_scope(void)
     65 /*
     66  * Function: 	var_push_scope 
     67  * Purpose:	Push a new variable scope onto the top of the stack.
     68  * Parameters:	None.
     69  * Returns:	Pointer to current scope as a cookie. 
     70  * Notes:	The cookie is useful to allow calling routine to know if the
     71  *		push was done, and also is passed to POP, and the pop is only
     72  *		done if the cookie matches the top of the queue. This can help 
     73  *		in control-c handing.
     74  */
     75 {
     76     var_scope_t	*vs;
     77     int		il;			/* Don't corrupt list */
     78 
     79     vs = (var_scope_t *)sal_alloc(sizeof(var_scope_t), "diag_scope");
     80     assert(vs);
     81 
     82     il = sal_splhi();
     83     vs->vs_next  = var_scope_list;
     84     vs->vs_local.v_next = vs->vs_local.v_prev = &vs->vs_local;
     85     vs->vs_local.v_name = vs->vs_local.v_value = NULL;
     86     var_scope_list = vs;		/* Bang - new scope */
     87     sal_spl(il);
     88     return((void *)vs);
     89 }
     90 
     91 void
     92 var_pop_scope(void *vs_cookie)
     93 /*
     94  * Function: 	var_pop_scope
     95  * Purpose:	Pop the current variable scope, and restore previous.
     96  * Parameters:	Cookie from PUSH, if does not match TOP of list, POP
     97  *		not done.
     98  * Returns:	Nothing.
     99  */
    100 {
    101     var_scope_t	*vs;
    102     var_t	*v;
    103     int		il = sal_splhi();
    104 
    105     vs = var_scope_list;
    106     if (vs_cookie == vs) {
    107 	var_scope_list = vs->vs_next;	/* Popped */
    108 	sal_spl(il);
    109 	for (v = vs->vs_local.v_next; v != &vs->vs_local; ) {
    110 	    sal_free(v->v_name);		/* Free name */
    111 	    sal_free(v->v_value);		/* Free value */
    112 	    v = v->v_next;		/* Next please */
    113 	    sal_free(v->v_prev);		/* Free last goober */
    114 	}
    115 	sal_free(vs);			/* Finally free scope */
    116     } else {
    117 	sal_spl(il);
    118     }
    119 }
    120 
    121 STATIC var_t 	*
    122 var_find_list(var_t *vl, const char *name)
    123 /*
    124  * Function: 	var_find_list
    125  * Purpose:	Find a variable in the given list.
    126  * Parameters:	vl - pointer to dummy entry at head of list.
    127  *		name - name of variable to find.
    128  * Returns:	NULL if failed, pointer to var_t if found.
    129  */
    130 {
    131     var_t	*v;
    132 
    133     for (v = vl->v_next; v != vl; v = v->v_next) {
    134         if (v->v_name != NULL && name != NULL) {
    135             if (sal_strcmp(v->v_name, name) == 0) {
    136                 return(v);
    137             }
    138         }
    139     }
    140     return(NULL);
    141 }
    142 
    143 STATIC var_t	*
    144 var_find(const char *name, int local, int global)
    145 /*
    146  * Function: 	var_find
    147  * Purpose:	Locate a variable.
    148  * Parameters:	name - name of variable to locate.
    149  *		local - TRUE if local scope should be checked.
    150  *		global- TRUE if global scope should be checked.
    151  * Returns:	Pointer to variable structure or NULL if failed.
    152  * Notes:	If local is TRUE, the local scope is always 
    153  *		checked before the global scope.
    154  */
    155 {
    156     var_t	*v = NULL;
    157 
    158     if (local && var_scope_list) {
    159 	v = var_find_list(&var_scope_list->vs_local, name);
    160     }
    161     if (global && !v) {
    162 	v = var_find_list(&var_global_list, name);
    163     }	
    164     return(v);
    165 }
    166 
    167 STATIC INLINE void
    168 var_delete(var_t *v)
    169 /*
    170  * Function: 	var_delete
    171  * Purpose:	Delete a variable from a list
    172  * Parameters:	v - pointer to variable to delete.
    173  * Returns:	Nothing.
    174  */
    175 {
    176     int	il = sal_splhi();			/* Don't corrupt list */
    177 
    178     v->v_prev->v_next = v->v_next;
    179     v->v_next->v_prev = v->v_prev;
    180     sal_spl(il);
    181     sal_free(v->v_name);
    182     sal_free(v->v_value);
    183     sal_free(v);
    184 }
    185 
    186 STATIC  void
    187 var_set_list(var_t *vl, const char *name, char *val)
    188 /*
    189  * Function:    var_set
    190  * Purpose: Set a variable to the specified value.
    191  * Parameters:  vl - pointer to dummy entry on head of var list.
    192  *              name - name of variable to set.
    193  *              val - value to set the variable to.
    194  * Returns: Nothing
    195  */
    196 {
    197     var_t   *v;
    198     char    *old_val_addr;
    199     char    *v_value = sal_strdup(val);
    200     int     il;
    201 
    202     assert(v_value);
    203 
    204     if (NULL != (v = var_find_list(vl, name))) {
    205         /* If already exists on list, replace value */
    206         il = sal_splhi();
    207         old_val_addr = v->v_value;
    208         v->v_value = v_value;
    209         sal_spl(il);
    210         sal_free(old_val_addr);
    211     } else {
    212         /* Otherwise, create a new entry and link it on the list */
    213         v = (var_t *)sal_alloc(sizeof(*v), "diag_var");
    214         assert(v);
    215         v->v_name = sal_strdup(name);
    216         assert(v->v_name);
    217         il = sal_splhi();
    218         v->v_prev  = vl->v_prev;
    219         v->v_next  = vl;
    220         v->v_prev->v_next = v;
    221         v->v_next->v_prev = v;
    222         v->v_value = v_value;
    223         sal_spl(il);
    224     }
    225 }
    226 
    227 cmd_result_t
    228 var_set_system(char *name, char *value)
    229 /*
    230  * Function: 	var_set_system
    231  * Purpose:	Add a system variable (ie, beginning with '_').
    232  * Parameters:	name  - name of variable to add
    233  *		value - value of variable.
    234  * Returns:	CMD_OK - Variable set.
    235  *		CMD_FAIL - Invalid variable name.
    236  */
    237 {
    238     if (*name != PARSE_VARIABLE_SYSTEM) {
    239 	return(CMD_FAIL);
    240     } else {
    241 	var_set_list(&var_global_list, name, value);
    242 	return(CMD_OK);
    243     }
    244 }
    245 
    246 int
    247 var_set(const char *name, char *value, int local, int system)
    248 /*
    249  * Function: 	var_set
    250  * Purpose:	Set a variable to the specified variable.
    251  * Parameters:	name - name of variable to set.
    252  *		value - value of variable to set.
    253  *		local - if TRUE, scope of variable is local.
    254  *		system - if TRUE, first character "_", otherwise, 
    255  *			first character can NOT be "_".
    256  * Returns:	0 - success, -1 - invalid name for <system> setting.
    257  */
    258 {
    259     if ((system && !VAR_IS_SYSTEM(name))||(!system && VAR_IS_SYSTEM(name))){
    260 	return(-1);
    261     }
    262     if (local && var_scope_list) {
    263 	var_set_list(&var_scope_list->vs_local, name, value);
    264     } else {
    265 	var_set_list(&var_global_list, name, value);
    266     }
    267     return(0);
    268 }
    269 
    270 int
    271 var_set_integer(const char *name, int value, int local, int system)
    272 /*
    273  * Function: 	var_set_integer
    274  * Purpose:	Set a variable to an integer value.
    275  * Parameters:	name - name of variable.
    276  *		value - integer value to set to.
    277  *		local - TRUE if local variable.
    278  *		system - TRUE if system variable.
    279  * Returns:	0 - success, -1 - invalid name for <system> setting.
    280  */
    281 {
    282     char	v_str[12];
    283     
    284     sal_sprintf(v_str, "%d", value);
    285     return(var_set(name, v_str, local, system));
    286 }
    287 
    288 int
    289 var_set_hex(const char *name, int value, int local, int system)
    290 /*
    291  * Function: 	var_set_integer
    292  * Purpose:	Set a variable to an integer value.
    293  * Parameters:	name - name of variable.
    294  *		value - integer value to set to.
    295  *		local - TRUE if local variable.
    296  *		system - TRUE if system variable.
    297  * Returns:	0 - success, -1 - invalid name for <system> setting.
    298  */
    299 {
    300     char	v_str[12];
    301     
    302     sal_sprintf(v_str, "0x%04x", value);
    303     return(var_set(name, v_str, local, system));
    304 }
    305 
    306 cmd_result_t
    307 var_unset_system(const char *name)
    308 /*
    309  * Function: 	var_unset_system
    310  * Purpose:	Delete a system defined variable.
    311  * Parameters:	name - name of variable to delete.
    312  * Returns:	CMD_OK - success
    313  *		CMD_FAIL - variable not found or invalid name.
    314  */
    315 {
    316     var_t	*v;
    317 
    318     if (*name != PARSE_VARIABLE_SYSTEM) {
    319 	return(CMD_FAIL);
    320     } 
    321     v = var_find(name, FALSE, TRUE);
    322     if (!v) {
    323 	return(CMD_FAIL);
    324     } else {
    325 	var_delete(v);
    326 	return(CMD_OK);
    327     }
    328 }
    329 
    330 int
    331 var_unset(const char *name, int local, int global, int system)
    332 /*
    333  * Function: 	var_unset
    334  * Purpose:	Unset a variable
    335  * Parameters:	name - name of variable to unset.
    336  *		local - if true, variable is looked for on local list
    337  *		global - if TRUE, variable is looked for on global
    338  *			list.
    339  *		system - if TRUE, system variables may be operated on.
    340  * Returns:	0 - OK
    341  *		-1 - failed due to system setting.
    342  */
    343 {
    344     var_t	*v;
    345 
    346     if ((system && !VAR_IS_SYSTEM(name)) || (!system && VAR_IS_SYSTEM(name))) {
    347 	return(-1);
    348     }
    349     v = var_find(name, local, global);
    350     if (!v) {
    351 	return(-1);
    352     } else {
    353 	var_delete(v);
    354 	return(0);
    355     }
    356 }
    357 
    358 STATIC	INLINE void
    359 var_display_entry(var_t *v)
    360 /*
    361  * Function: 	var_display_entry
    362  * Purpose:	Print the name and value of a specific variable.
    363  * Parameters:	v - pointer to variable to display.
    364  * Returns:	Nothing.
    365  */
    366 {
    367     cli_out("%20s = %-20s\n", v->v_name, v->v_value);
    368 }
    369 
    370 
    371 STATIC void
    372 var_display_list(char *s, var_t *vl)
    373 /*
    374  * Function: 	var_display_list
    375  * Purpose:	Display an entire list of variables.
    376  * Parameters:	s - String to ID list.
    377  *		vl - pointer to dummy entry at head of list.
    378  * Returns:	Nothing.
    379  */
    380 {
    381     var_t	*v;
    382 
    383     cli_out("\n%20s | %-20s\n"
    384             "---------------------+---------------------\n",
    385             s, "Value");
    386     for (v = vl->v_next; v != vl; v = v->v_next) {
    387 	var_display_entry(v);
    388     }
    389     cli_out("-------------------------------------------\n");
    390 }
    391 
    392 char var_display_usage[] = 
    393     "Parameters: [local|global|all]\n\t"
    394     "Display variables and values. If no options are supplied, all local\n\t"
    395     "variables in the current scope and global variables are displayed.\n\t"
    396     "Options have the following meanings:\n\t"
    397     "\tlocal\t- display only local variables in the current scope.\n\t"
    398     "\tglobal\t- display all global (exported) variables\n\t"
    399     "\tall\t- display all variables in all scopes\n"
    400     VAR_SYSTEM_STRING;
    401 
    402 cmd_result_t
    403 var_display(int u, args_t *a)
    404 /*
    405  * Function: 	var_display
    406  * Purpose:	Display variable information.
    407  * Parameters:	u - unit number (ignored)
    408  *		a - pointer to argument list.
    409  * Returns:	CMD_OK/CMD_FAIL/CMD_USAGE.
    410  */
    411 {
    412     int	do_local  = FALSE,
    413         do_global = FALSE,
    414         do_all    = FALSE;
    415 
    416     COMPILER_REFERENCE(u);
    417 
    418     if (ARG_CNT(a) == 0) {		/* everything */
    419 	do_local  = TRUE;
    420 	do_global = TRUE;
    421     } else if (ARG_CNT(a) != 1) {
    422 	return(CMD_FAIL);
    423     } else if (!sal_strcasecmp("local", _ARG_CUR(a))) { /* Local only */
    424 	do_local = TRUE;
    425     } else if (!sal_strcasecmp("global", _ARG_CUR(a))) { /* Global only  */
    426 	do_global = TRUE;
    427     } else if (!sal_strcasecmp("all", _ARG_CUR(a))) { /* All scopes */
    428 	do_all = TRUE;
    429 	do_global = TRUE;
    430     }
    431     if (do_all) {
    432 	var_scope_t *vs;		/* Variable Scope*/
    433 	int	l;			/* Level */
    434 	char	l_str[64];
    435 	for (l = 1, vs = var_scope_list; vs; vs = vs->vs_next, l++) {
    436 	    sal_sprintf(l_str, "Scope Level %d", l);
    437 	    var_display_list(l_str, &vs->vs_local);
    438 	}
    439     } else if (do_local) {
    440         if (var_scope_list) {
    441             var_display_list("Local Variables", &var_scope_list->vs_local);
    442         }
    443     }
    444     if (do_global) {
    445 	var_display_list("Global Variables", &var_global_list);
    446     }
    447     return(CMD_OK);
    448 }
    449 
    450 char var_export_usage[] = 
    451     "Parameters: <variable> [<value>]\n\t"
    452     "Set variable <variable> to a specific value <value>, and export it\n\t"
    453     "making it visible in all scopes. If <value> is not present, the\n\t"
    454     "variable is removed from the global scope.\n"
    455     VAR_SYSTEM_STRING;
    456 
    457 /*ARGSUSED*/
    458 cmd_result_t
    459 var_export(int u, args_t *a)
    460 /*
    461  * Function: 	var_export
    462  * Purpose:	Create a global variable visible from anywhere.
    463  * Parameters:	u - unit (IGNORED)
    464  *		a - arguments
    465  * Returns: CMD_OK/CMD_FAIL
    466  */
    467 {
    468     char	*name, *value;
    469     int		rv = 0;
    470 
    471     COMPILER_REFERENCE(u);
    472 
    473     switch(ARG_CNT(a)) {
    474     case 0:
    475 	var_display_list("Global Variables", &var_global_list);
    476 	break;
    477     case 1:				/* Remove variable */
    478 	rv = var_unset(ARG_GET(a), FALSE, TRUE, FALSE);
    479 	break;
    480     case 2:				/* Add variable */
    481 	name = ARG_GET(a);
    482 	value = ARG_GET(a);
    483 	if (NULL != var_find(name, TRUE, FALSE)) {
    484 	    cli_out("%s: Warning: variable %s shadowed by local variable\n", 
    485                     ARG_CMD(a), name);
    486 	}
    487 	rv = var_set(name, value, FALSE, FALSE);
    488 	break;
    489     default:				/* Error */
    490 	return(CMD_USAGE);
    491     }
    492     return(rv ? CMD_FAIL : CMD_OK);
    493 }
    494 
    495 char var_local_usage[] = 
    496     "Parameters: <variable> [<value>]\n\t"
    497     "Set variable <variable> to a specific value <value>, in the local\n\t"
    498     "scope only. Variable in the local scope are not visible in\n\t"
    499     "recursive diag shells or in rc load files.\n\t"
    500     VAR_SYSTEM_STRING;
    501 
    502 cmd_result_t
    503 var_local(int u, args_t *a)
    504 /*
    505  * Function: 	var_local
    506  * Purpose:	Set/Remove a local variable.
    507  * Parameters:	u - unit number (ignored)
    508  *		a -arguments, either a variable name only to delete, 
    509  *		   or a variable name and a value.
    510  * Returns:	CMD_OK or CMD_FAIL if variable not found for removal
    511  *		or attempt to set/remove a system variable.
    512  *		CMD_USAGE for invalid number of arguments.
    513  */
    514 {
    515     char	*name, *value;
    516     int		rv = 0;
    517 
    518     COMPILER_REFERENCE(u);
    519 
    520     switch(ARG_CNT(a)) {
    521     case 0:
    522 	var_display_list("Local Variables", &var_scope_list->vs_local);
    523 	break;
    524     case 1:				/* Remove variable */
    525 	rv = var_unset(ARG_GET(a), TRUE, FALSE, FALSE);
    526 	break;
    527     case 2:				/* Add variable */
    528 	name = ARG_GET(a);
    529 	value= ARG_GET(a);
    530 	rv = var_set(name, value, TRUE, FALSE);
    531 	break;
    532     default:				/* Error */
    533 	return(CMD_USAGE);
    534     }
    535     return(rv ? CMD_FAIL : CMD_OK);
    536 }
    537 
    538 char	*
    539 var_get(const char *name)
    540 /*
    541  * Function: 	var_get
    542  * Purpose:	Perform normal lookup for a variable in the current scope and
    543  *		then on the global list.
    544  * Parameters:	name - name of variable to lookup.
    545  * Returns:	NULL - not found
    546  *		!NULL - pointer to value of variable.
    547  */
    548 {
    549     var_t	*v;
    550     
    551     v = var_find(name, TRUE, TRUE);
    552     return(v ? v->v_value : NULL);
    553 }