1 /*
2  *                     OpenBIOS - free your system!
3  *                         ( FCode tokenizer )
4  *
5  *  This program is part of a free implementation of the IEEE 1275-1994
6  *  Standard for Boot (Initialization Configuration) Firmware.
7  *
8  *  Copyright (C) 2001-2005 Stefan Reinauer, <stepan@openbios.org>
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; version 2 of the License.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
22  *
23  */
24 
25 /* **************************************************************************
cand_destructor(void * arg)26  *
27  *      General-purpose support functions for
28  *          User-defined command-line compilation-control symbols
29  *
30  *      (C) Copyright 2005 IBM Corporation.  All Rights Reserved.
31  *      Module Author:  David L. Paktor    dlpaktor@us.ibm.com
32  *
33  **************************************************************************** */
34 
35 /* **************************************************************************
36  *
37  *      The syntax for user-defined command-line compilation-control symbols
38  *          is <NAME>[=<VALUE>]
39  *
40  *      The name is always required; the equal-sign and value are optional.
41  *          If you wish the "value" to contain spaces or quotes, you can
42  *          accomplish that using the shell escape conventions.
43  *
44  *      The operations that can be performed upon these symbols will be
45  *          described by the operators that use them as operands, but,
46  *          broadly speaking, the tests will either be to simply verify
47  *          the existence of a symbol, or to evaluate the defined value.
48  *
49  *      Once a symbol is defined on the command-line, it stays in effect
50  *          for the duration of the entire batch of tokenizations (i.e.,
51  *          if there are multiple input files named on the command line).
52  *          Also, there are no symbols defined at the outset.  Therefore,
53  *          there is no need for either an "init" or a "reset" routine.
54  *
55  **************************************************************************** */
56 
57 /* **************************************************************************
58  *
59  *      User-defined command-line compilation-control symbols are
60  *          implemented as a String-Substitution-type vocabulary.
61  *
62  **************************************************************************** */
63 
64 /* **************************************************************************
65  *
66  *      Functions Exported:
67  *          add_user_symbol            Add a user-defined symbol to the list
68  *          exists_as_user_symbol      Confirm whether a given name exists
69  *                                         as a user-defined symbol.
70  *          eval_user_symbol           Evaluate the value assigned to a user
71  *                                         symbol.
72  *          list_user_symbols          Print the list of user-defined symbols
73  *                                         for the Logfile.
74  *
75  **************************************************************************** */
76 
77 /* **************************************************************************
78  *
79  *      Still to be done:
80  *          Convert the handling of user-defined symbols to the T.I.C.
81  *              data-structure and its support routines.  This should
82  *              eliminate any further need of String-Substitution-type
83  *              vocabularies.  User-defined symbols will, however, still
84  *              need to be a separate vocabulary from the Global, because
85  *              they are required to stay in effect for the duration of
86  *              the entire batch of tokenizations...
87  *          (Afterthought:  This is only true for user-defined symbols that
88  *              were created on the command-line; if we ever allow symbols
89  *              to be defined in the Source file, they should be as volatile
90  *              as anything else that comes from a source file...
91  *           Appending source-file-derived user-defined symbols to the Global
92  *              Vocabulary could be a quasi-simple way to accomplish this.)
93  *
94  *          Enable the definition of user-symbols from the Source file, using
95  *              a syntax like:  [define] symbol   or  [define] symbol=<value>
96  *              (How to allow spaces into the <value>?  Maybe make the syntax
97  *              [define] symbol = <value components to end of line>
98  *              delimited in a manner similar to Macro definitions.
99  *          There might be a need to be able to  [undefine]  a user-symbol
100  *              that would entail defining an  unlink_tic_entry  function.
101  *              Not difficult; just keeping this around as a reminder...
102  *
103  **************************************************************************** */
104 
105 
106 
107 #include <stdio.h>
108 #include <stdlib.h>
109 #if defined(__linux__) && ! defined(__USE_BSD)
110 #define __USE_BSD
111 #endif
112 #include <string.h>
113 
114 #include "errhandler.h"
115 #include "strsubvocab.h"
116 #include "usersymbols.h"
117 #include "scanner.h"
118 
119 
120 /* **************************************************************************
121  *
122  *              Internal Static Variables
123  *      user_symbol_list          Pointer to the "tail" of the list of
124  *                                    user-defined symbols.
125  *      user_symbol_count         Count of how many are defined
126  *
127  **************************************************************************** */
128 
129 static str_sub_vocab_t *user_symbol_list = NULL;
130 static int user_symbol_count = 0;
131 
132 /* **************************************************************************
133  *
134  *      Function name:  add_user_symbol
135  *      Synopsis:       Add a user-defined symbol to the list
136  *
137  *      Inputs:
138  *         Parameters:
icem_rcand_add(struct icem * icem,enum ice_cand_type type,unsigned compid,uint32_t prio,const struct sa * addr,const struct sa * rel_addr,const struct pl * foundation)139  *             raw_symb             The string as supplied on the command-line.
140  *         Local Static Variables:
141  *             user_symbol_list     Pointer to the list of user-defined symbols.
142  *
143  *      Outputs:
144  *         Returned Value:                NONE
145  *         Local Static Variables:
146  *             user_symbol_list     Will be updated.
147  *             user_symbol_count    Will be incremented
148  *         Memory Allocated:
149  *             for the string(s) and the new entry
150  *         When Freed?
151  *             Never.  Well, upon termination of the program.  User-defined
152  *                 symbols endure for the entire batch of tokenizations.
153  *
154  *      Process Explanation:
155  *          The string in  raw_symb  may or may not include the optional
156  *              equal-sign and value pair.  If the equal-sign is present,
157  *              the remainder of the string will become the "value" that
158  *              will be returned by the "lookup" routine.
159  *          Memory for the name string and for the value, if there is one,
160  *              will be allocated here, in one step.  Memory for the data
161  *              structure itself will be allocated by the support routine.
162  *
163  **************************************************************************** */
164 
165 void add_user_symbol(char *raw_symb)
166 {
167     char *symb_nam;
168     char *symb_valu;
169 
170     symb_nam = strdup(raw_symb);
171     symb_valu = strchr(symb_nam,'=');
172     if ( symb_valu != NULL )
173     {
174 	*symb_valu = 0;
175 	symb_valu++;
176     }
177     add_str_sub_entry(symb_nam, symb_valu, &user_symbol_list );
178     user_symbol_count++;
179 }
180 
181 
182 /* **************************************************************************
183  *
184  *      Function name:  exists_as_user_symbol
185  *      Synopsis:       Confirm whether a given name exists
186  *                      as a user-defined symbol.
187  *
188  *      Inputs:
189  *         Parameters:
190  *             symb_nam             The name for which to look.
191  *         Local Static Variables:
192  *             user_symbol_list     Pointer to the list of user-defined symbols.
193  *
194  *      Outputs:
195  *         Returned Value:      TRUE if the name is found
196  *
197  **************************************************************************** */
198 
199 bool exists_as_user_symbol(char *symb_nam)
200 {
201     bool retval;
202 
203     retval = exists_in_str_sub(symb_nam, user_symbol_list );
204     return (retval);
205 }
206 
207 /* **************************************************************************
208  *
209  *      Function name:  eval_user_symbol
icem_cand_find(const struct list * lst,unsigned compid,const struct sa * addr)210  *      Synopsis:       Evaluate the value assigned to a user-symbol.
211  *
212  *      Associated Tokenizer directive (synonyms):      [DEFINED]
213  *                                                      #DEFINED
214  *                                                      [#DEFINED]
215  *
216  *      Syntax Notes:
217  *          (1)  The User-Defined-Symbol must appear
218  *                   on the same line as the directive.
219  *          (2)  This is not (yet) implemented in contexts that
220  *                   directly read input from the stream, e.g.,
221  *                   after  [']  or after  H#  etc.
222  *
223  *      Inputs:
224  *         Parameters:
225  *             symb_nam             Name of the User-Defined-Symbol to evaluate
226  *         Local Static Variables:
227  *             user_symbol_list     Pointer to the list of user-defined symbols.
228  *
229  *      Outputs:
230  *         Returned Value:          NONE
231  *         The assigned value will be tokenized.
232  *
233  *      Error Detection:
234  *          Calling routine is responsible for verifying that the user-symbol
235  *              is on the same line as the directive.
236  *          ERROR if the symbol is not found
237  *          WARNING if the symbol has no assigned value.
238  *
239  *      Process Explanation:
240  *          Look up the parameter in the User Symbol List,
241  *          If it is not found, issue an ERROR and do nothing further.
242  *          If it is found, attempt to retrieve its associated value
243  *          If it has no associated value, issue a WARNING and
244  *              do nothing further.  Otherwise...
245  *          Interpret the associated value as though it were source.
246  *
247  *      Still to be done:
248  *          Hook-in this routine to the processing of:  [']  F[']  H#  FLOAD
249  *              etc., and wherever else it might be needed or useful.
250  *
251  **************************************************************************** */
252 
253 void eval_user_symbol( char *symb_nam)
254 {
255     str_sub_vocab_t *found = NULL;
256 
257 
258     found = lookup_str_sub( symb_nam, user_symbol_list );
259     if ( found == NULL )
260     {
261         tokenization_error ( TKERROR,
262 	    "Command-line symbol %s is not defined.\n", symb_nam);
263     }else{
264 	char *symb_valu = found->alias;
265 
266 	if ( symb_valu == NULL )
267 	{
268             tokenization_error ( WARNING,
269 		"No value assigned to command-line symbol %s\n", symb_nam );
270 	}else{
271 	    eval_string( symb_valu );
272 	}
273     }
274 
275 }
276 /* **************************************************************************
277  *
icem_cands_debug(struct re_printf * pf,const struct list * lst)278  *      Function name:  list_user_symbols
279  *      Synopsis:       Print the list of user symbols for the Logfile.
280  *
281  *      Inputs:
282  *         Parameters:              NONE
283  *         Local Static Variables:
284  *             user_symbol_list     Pointer to the list of user-defined symbols.
285  *             user_symbol_count    Count of user-defined symbols.
286  *
287  *      Outputs:
288  *         Returned Value:          NONE
289  *         Printout:                List of user symbols and their definitions;
290  *                                      nothing if user_symbol_list is NULL.
291  *
292  *      Process Explanation:
293  *          We want to display the symbols in the same order they were created.
294  *          We will:
295  *              Allocate a temporary array of pointers.
296  *              Step backwards through the linked-list of symbols, and
297  *                  enter their pointers into the array.  The array order
298  *                  reflects the backward-linked order of the linked-list
299  *                  of symbols is kept and searched,
300  *              Collect the maximum length of the symbol names.
301  *              Step through the array in the reverse order, to follow the
302  *                  order in which the symbols were defined.
303  *                  Check for a duplicate of the current symbol name:
304  *                      Look backwards through the array, at the names we
305  *                          have not yet printed, which were defined later.
306  *                          Since the later-defined value will prevail, the
307  *                          notation should be on the earlier one.
308  *                  Print the current name
309  *                  Use the maximum name-length to space the equal-signs or
310  *                      duplicate-name notation, as required, evenly.
311  *              Free the temporary array.
312  *
313  *      Revision History:
314  *          Updated Thu, 07 Sep 2006 by David L. Paktor
315  *              Report duplicated symbol names.
316  *
317  *      Still to be done:
318  *          Space the duplicate-name notation evenly; line it up past
319  *               the longest name-with-value.
320  *
321  **************************************************************************** */
322 
323 void list_user_symbols(void )
324 {
325     str_sub_vocab_t *curr;
326 
327     if ( user_symbol_list != NULL )
328     {
329 	/*  Collect the pointers and max length  */
330 	str_sub_vocab_t **symb_ptr;
331 	int indx = 0;
332 	int maxlen = 0;
333 
334 	symb_ptr = (str_sub_vocab_t **)safe_malloc(
335 	   (sizeof(str_sub_vocab_t *) * user_symbol_count),
336 	       "collecting user-symbol pointers" );
337 
338 	for (curr = user_symbol_list ; curr != NULL ; curr=curr->next)
339 	{
340             symb_ptr[indx] = curr;
341 	    indx++;
342 	    if ( strlen(curr->name) > maxlen ) maxlen = strlen(curr->name);
343 	}
344 
345 	/*  Now print 'em out  */
346 	printf("\nUser-Defined Symbols:\n");
347 	while ( indx > 0 )
348 	{
349 	    bool is_dup;
350 	    int dup_srch_indx;
351 	    indx--;
352 	    curr = symb_ptr[indx];
353 
354 	    /*  Detect duplicate names.  */
355 	    dup_srch_indx = indx;
356 	    is_dup = FALSE;
357 	    while ( dup_srch_indx > 0 )
358 	    {
359 		str_sub_vocab_t *dup_cand;
360 		dup_srch_indx--;
361 		dup_cand = symb_ptr[dup_srch_indx];
362 		if ( strcmp( curr->name, dup_cand->name) == 0 )
363 		{
364 		    is_dup = TRUE;
365 		    break;
366 		}
367 	    }
368 
369 	    printf("\t%s",curr->name);
370 
371 	    if ( ( curr->alias != NULL ) || is_dup )
372 	    {
373 	        int strindx;
374 		for ( strindx = strlen(curr->name) ;
375 		      strindx < maxlen ;
376 		      strindx++ )
377 		{
378 		    printf(" ");
379 		}
380 	    }
381 	    if ( curr->alias != NULL )
382 	    {
383 		printf(" = %s",curr->alias);
384 	    }
385 	    if ( is_dup )
386 	    {
387 		printf(" *** Over-ridden" );
388 	    }
389 	    printf("\n");
390 	}
391 	free(symb_ptr);
392     }
393 }
394