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 /* **************************************************************************
26  *
27  *      General-purpose support functions for
28  *      Threaded Interpretive Code (T. I. C.)-type vocabularies
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  *      We are going to implement a strategy that takes better advantage
38  *          of the concept of Threaded Interpretive Code  (well, okay,
39  *          it won't really be interpretive ... )  We will use it to
40  *          implement a small (but expandable) subset of FORTH-like
41  *          commands in Tokenizer-Escape mode, as well as a few other
42  *          things, such as conditional-tokenization.
43  *
44  *      The Threaded Interpretive Code Header data structure is described
45  *          in detail in the accompanying  ticvocab.h  header-file.
46  *
47  *      In most cases, the contents of a beginning portion of the vocabulary
48  *          are known at compile-time, and later parts are added by the
49  *          user at run-time.  (The linked-list structure is needed to allow
50  *          for that.)  We can initialize the known start of the vocabulary
51  *          easily, except for the link-pointers, as an array.
52  *      We can either explicitly state an index for each entry's link-pointer
53  *          to the previous entry (which can become a problem to maintain) or
54  *          have a function to initialize the links dynamically, at run-time.
55  *      I think I will (regretfully, resignedly) choose the latter.
56  *
57  *      We will define a few general-purpose functions for dealing with
58  *          T. I. C. -type vocabularies.  Eventually, it might be a good
59  *          idea to convert all the vocabularies to this structure...
60  *
61  **************************************************************************** */
62 
63 /* **************************************************************************
64  *
65  *
66  *      Revision History:
67  *          Mon, 19 Dec 2005 by David L. Paktor
68  *          Begin converting most, if not all, of the vocabularies to
69  *              T. I. C. -type structure.
70  *
71  **************************************************************************** */
72 
73 
74 /* **************************************************************************
75  *
76  *      Functions Exported:
77  *          init_tic_vocab        Initialize a TIC_HDR -type vocabulary
78  *          add_tic_entry         Add an entry to a TIC_HDR -type vocabulary
79  *          lookup_tic_entry      Look for a name in a TIC_HDR -type vocabulary
80  *          handle_tic_vocab      Perform a function in a TIC_HDR -type vocab
81  *          exists_in_tic_vocab   Confirm whether a given name exists in a
82  *                                    TIC_HDR -type vocabulary
83  *          create_tic_alias      Duplicate the behavior of one name with
84  *                                     another name.  Return a "success" flag.
85  *          reset_tic_vocab       Reset a given TIC_HDR -type vocabulary to
86  *                                    its "Built-In" position.
87  *
88  **************************************************************************** */
89 
90 
91 /* **************************************************************************
92  *
93  *          Global Variables Exported
94  *              tic_found       The entry, in a TIC_HDR -type vocabulary,
95  *                                  that has just been found and is being
96  *                                  "handled".  Needed for protection against
97  *                                  recursion in a User-defined Macro (which
98  *                                  should occur only rarely).
99  *
100  **************************************************************************** */
101 
102 
103 #include <stdlib.h>
104 #include <string.h>
105 
106 #include "ticvocab.h"
107 #include "errhandler.h"
108 #include "tracesyms.h"
109 #include "scanner.h"
110 #include "devnode.h"
111 #include "vocabfuncts.h"
112 
113 tic_hdr_t *tic_found;
114 
115 /* **************************************************************************
116  *
117  *      Function name:  init_tic_vocab
118  *      Synopsis:       Dynamically initialize the link-pointers
119  *                          of the.given TIC_HDR -type vocabulary
120  *
121  *      Inputs:
122  *         Parameters:
123  *             tic_vocab_tbl       Pointer to the initial TIC_HDR vocab array
124  *             max_indx            Maximum Index of the initial array.
125  *             tic_vocab_ptr       Pointer to the vocab "tail"
126  *
127  *      Outputs:
128  *         Returned Value:         None
129  *         Global Variables:
130  *              The link-fields of the initial TIC_HDR vocab array entries
131  *                  will be filled in.
132  *         Supplied Pointers:
133  *             *tic_vocab_ptr       Points to the last element in the array
134  *
135  *      Process Explanation:
136  *          The value that  tic_vocab_ptr  has upon entry to the routine
137  *              (which may point to the end of another array which is to
138  *              precede this one in the voacbulary) gets entered into
139  *              the link-pointer field of the first element of the array.
140  *          For this reason, it is important that all TIC_HDR vocabulary
141  *              pointers that will be passed to this routine have their
142  *              initial values explicitly declared NULL.
143  *          If the user has asked to Trace any built-in name, the support
144  *              routine will set its  tracing  field and dispay a message.
145  *
146  **************************************************************************** */
147 
init_tic_vocab(tic_hdr_t * tic_vocab_tbl,int max_indx,tic_hdr_t ** tic_vocab_ptr)148 void init_tic_vocab( tic_hdr_t *tic_vocab_tbl,
149                          int max_indx,
150 			     tic_hdr_t **tic_vocab_ptr)
151 {
152     int indx;
153     for ( indx = 0 ; indx < max_indx ; indx++ )
154     {
155         tic_vocab_tbl[indx].next = *tic_vocab_ptr;
156 	*tic_vocab_ptr = &tic_vocab_tbl[indx];
157 	trace_builtin( &tic_vocab_tbl[indx]);
158     }
159 }
160 
161 
162 /* **************************************************************************
163  *
164  *      Function name:  make_tic_entry
165  *      Synopsis:       Construct a new entry to a TIC_HDR -type vocab-list
166  *                          but do not add it to a vocabulary
167  *
168  *      Inputs:
169  *         Parameters:
170  *             tname         Pointer to space containing the name of the entry
171  *             tfunct        Pointer to the routine the new entry will call
172  *             tparam        The "parameter field" value (may be a pointer)
173  *             fw_defr       FWord Token of the entry's Definer
174  *             pfldsiz       Size of "param field" (if a pointer to alloc'd mem)
175  *             is_single     TRUE if entry is a single-token FCode
176  *             ign_fnc       Pointer to "ignoring" routine for new entry
177  *             trace_this    TRUE if new entry is to be "Traced"
178  *             tic_vocab     Address of the variable that holds the latest
179  *                               pointer to the "tail" of the T.I.C.-type
180  *                               vocab-list to which we are adding.
181  *
182  *      Outputs:
183  *         Returned Value:   Pointer to the new entry
184  *         Memory Allocated:
185  *             For the new entry.
186  *         When Freed?
187  *             When reset_tic_vocab() is applied to the same vocab-list.
188  *
189  *      Error Detection:
190  *          Failure to allocate memory is a Fatal Error.
191  *
192  *      Process Explanation:
193  *          The name pointer is presumed to already point to a stable,
194  *              newly-allocated memory-space.  If the parameter field is
195  *              actually a pointer, it, too, is presumed to already have
196  *              been allocated.
197  *          Memory will be allocated for the entry itself and the given
198  *              data will be placed into its fields.
199  *
200  *      Extraneous Remarks:
201  *          This is a retro-fit; it's a factor of the add_tic_entry()
202  *              routine, whose functionality has been expanded to include
203  *              issuing the Trace-Note and Duplication Warning messages.
204  *              Having it separate allows it to be called (internally) by
205  *              create_split_alias(), which has special requirements for
206  *              its call to trace_creation()
207  *
208  **************************************************************************** */
209 
make_tic_entry(char * tname,void (* tfunct)(),TIC_P_DEFLT_TYPE tparam,fwtoken fw_defr,int pfldsiz,bool is_single,void (* ign_fnc)(),bool trace_this,tic_hdr_t ** tic_vocab)210 static tic_hdr_t *make_tic_entry( char *tname,
211                         void (*tfunct)(),
212                              TIC_P_DEFLT_TYPE tparam,
213                                  fwtoken fw_defr,
214 				     int pfldsiz,
215                                          bool is_single,
216                                          void (*ign_fnc)(),
217                                                bool trace_this,
218                                              tic_hdr_t **tic_vocab )
219 {
220     tic_hdr_t *new_entry;
221 
222     new_entry = safe_malloc(sizeof(tic_hdr_t), "adding tic_entry");
223     new_entry->name              =  tname;
224     new_entry->next              = *tic_vocab;
225     new_entry->funct             =  tfunct;
226     new_entry->pfield.deflt_elem =  tparam;
227     new_entry->fword_defr        =  fw_defr;
228     new_entry->is_token          =  is_single;
229     new_entry->ign_func          =  ign_fnc;
230     new_entry->pfld_size         =  pfldsiz;
231     new_entry->tracing           =  trace_this;
232 
233     return( new_entry);
234 }
235 
236 
237 /* **************************************************************************
238  *
239  *      Function name:  add_tic_entry
240  *      Synopsis:       Add an entry to the given TIC_HDR -type vocabulary;
241  *                          issue the Creation Tracing and Duplicate-Name
242  *                          messages as applicable.
243  *
244  *      Inputs:
245  *         Parameters:
246  *             tname             Pointer to space containing entry's new name
247  *             tfunct            Pointer to the routine the new entry will call
248  *             tparam            The "parameter field" value (may be a pointer)
249  *             fw_defr           FWord Token of the entry's Definer
250  *             pfldsiz           Size of "param field" (if a ptr to alloc'd mem)
251  *             is_single         TRUE if entry is a single-token FCode
252  *             ign_fnc           Pointer to "ignoring" routine for new entry
253  *          NOTE:  No  trace_this  param here; it's only in make_tic_entry()
254  *             tic_vocab         Address of the variable that holds the latest
255  *                                   pointer to the "tail" of the T.I.C.-type
256  *                                   vocab-list to which we are adding.
257  *         Global Variables:
258  *             scope_is_global   TRUE if "global" scope is in effect
259  *                                  (passed to "Trace-Creation" message)
260  *
261  *      Outputs:
262  *         Returned Value:       NONE
263  *         Supplied Pointers:
264  *             *tic_vocab        Will point to new entry
265  *         Printout:
266  *             "Trace-Creation" message
267  *
268  *      Error Detection:
269  *          Warning on duplicate name (subject to command-line control)
270  *
271  *      Process Explanation:
272  *          The entry itself will be created by the  make_tic_entry()  routine.
273  *          This routine will test whether the new name is to be Traced,
274  *              and will pass that datum to the  make_tic_entry()  routine.
275  *          If the new name is to be Traced, issue a Creation Tracing message.
276  *              (We want it to appear first).  Use the new entry.
277  *          Because this routine will not be called for creating aliases, the
278  *              second param to  trace_creation()  is NULL.
279  *          Do the duplicate-name check _before_ linking the new entry in to
280  *              the given vocabulary.  We don't want the duplicate-name test
281  *              to find the name in the new entry, only in pre-existing ones...
282  *          Now we're ready to update the given pointer-to-the-tail-of-the-
283  *              -vocabulary to point to the new entry.
284  *
285  **************************************************************************** */
286 
add_tic_entry(char * tname,void (* tfunct)(),TIC_P_DEFLT_TYPE tparam,fwtoken fw_defr,int pfldsiz,bool is_single,void (* ign_fnc)(),tic_hdr_t ** tic_vocab)287 void add_tic_entry( char *tname,
288                         void (*tfunct)(),
289                              TIC_P_DEFLT_TYPE tparam,
290                                  fwtoken fw_defr,
291 				     int pfldsiz,
292                                          bool is_single,
293 					   void (*ign_fnc)(),
294 					       tic_hdr_t **tic_vocab )
295 {
296     bool trace_this = is_on_trace_list( tname);
297     tic_hdr_t *new_entry = make_tic_entry( tname,
298 			       tfunct,
299 			           tparam,
300 				       fw_defr, pfldsiz,
301 				           is_single,
302 					       ign_fnc,
303 						   trace_this,
304 						       tic_vocab );
305 
306     if ( trace_this )
307     {
308 	trace_creation( new_entry, NULL, scope_is_global);
309     }
310     warn_if_duplicate( tname);
311     *tic_vocab = new_entry;
312 
313 }
314 
315 /* **************************************************************************
316  *
317  *      Function name:  lookup_tic_entry
318  *      Synopsis:       Look for a name in the given TIC_HDR -type vocabulary
319  *
320  *      Inputs:
321  *         Parameters:
322  *             tname                The "target" name for which to look
323  *             tic_vocab            Pointer to the T. I. C. -type vocabulary
324  *                                      in which to search
325  *
326  *      Outputs:
327  *         Returned Value:          Pointer to the relevant entry, or
328  *                                      NULL if name not found.
329  *
330  *      Extraneous Remarks:
331  *          We don't set the global  tic_found  here because this routine
332  *              is not always called when the found function is going to
333  *              be executed; sometimes it is called for error-detection;
334  *              for instance, duplicate-name checking...
335  *
336  **************************************************************************** */
337 
lookup_tic_entry(char * tname,tic_hdr_t * tic_vocab)338 tic_hdr_t *lookup_tic_entry( char *tname, tic_hdr_t *tic_vocab )
339 {
340     tic_hdr_t *curr ;
341 
342     for (curr = tic_vocab ; curr != NULL ; curr=curr->next)
343     {
344         if ( strcasecmp(tname, curr->name) == 0 )
345 	{
346 	    break;
347 	}
348     }
349 
350     return ( curr ) ;
351 }
352 
353 /* **************************************************************************
354  *
355  *      Function name:  exists_in_tic_vocab
356  *      Synopsis:       Confirm whether the given name exists in the
357  *                      given TIC_HDR -type vocabulary
358  *
359  *      Inputs:
360  *         Parameters:
361  *             tname                The name for which to look
362  *             tic_vocab            Pointer to the T. I. C. -type vocabulary
363  *
364  *      Outputs:
365  *         Returned Value:          TRUE if name is found,
366  *
367  **************************************************************************** */
368 
exists_in_tic_vocab(char * tname,tic_hdr_t * tic_vocab)369 bool exists_in_tic_vocab( char *tname, tic_hdr_t *tic_vocab )
370 {
371     tic_hdr_t *found ;
372     bool retval = FALSE;
373 
374     found = lookup_tic_entry( tname, tic_vocab );
375     if ( found != NULL )
376     {
377 	retval = TRUE;
378     }
379 
380     return ( retval );
381 }
382 
383 
384 /* **************************************************************************
385  *
386  *      Function name:  create_split_alias
387  *      Synopsis:       Create an Alias in one TIC_HDR -type vocabulary
388  *                          for a word in (optionally) another vocabulary.
389  *                          Return a "success" flag.
390  *                          This is the work-horse for  create_tic_alias()
391  *
392  *      Associated FORTH word:                 ALIAS
393  *
394  *      Inputs:
395  *         Parameters:
396  *             old_name             Name of existing entry
397  *             new_name             New name for which to create an entry
398  *             *src_vocab           Pointer to the "tail" of the "Source"
399  *                                      TIC_HDR -type vocab-list
400  *             *dest_vocab          Pointer to the "tail" of the "Destination"
401  *                                      TIC_HDR -type vocab-list
402  *
403  *      Outputs:
404  *         Returned Value:          TRUE if  old_name  found in "Source" vocab
405  *         Supplied Pointers:
406  *             *dest_vocab          Will be updated to point to the new entry
407  *         Memory Allocated:
408  *             For the new entry, by the support routine.
409  *         When Freed?
410  *             When reset_tic_vocab() is applied to "Destination" vocab-list.
411  *         Printout:
412  *             "Trace-Creation" message
413  *
414  *      Error Detection:
415  *          Warning on duplicate name (subject to command-line control)
416  *
417  *      Process Explanation:
418  *          Both the "old" and "new" names are presumed to already point to
419  *              stable, freshly allocated memory-spaces.
420  *          Even if the "old" entry's  pfld_size  is not zero, meaning its
421  *              param-field is a pointer to allocated memory, we still do
422  *              not need to copy it into a freshly allocated memory-space,
423  *              as long as we make the new alias-entry's  pfld_size  zero:
424  *              the reference to the old space will work, and the old
425  *              entry's param-field memory space will not be freed with
426  *              the alias-entry but only with the "old" entry.
427  *          We will do both the "Creation-Tracing" announcement and the
428  *              Duplicate Name Warning here.  "Tracing" happens either if
429  *              the entry for the old name has its  tracing  flag set, or
430  *              if the new name is on the trace-list.  The "source" vocab
431  *              and the "dest" vocab can only be different when the "old"
432  *              name has defined Global scope.  We will pass that along
433  *              to the  trace_creation()  routine.
434  *          We're doing the "Tracing" and Duplicate-Name functions because
435  *              we're applying the "Tracing" message to the "old" name's
436  *              entry.  Because of this, we must call  make_tic_entry()  to
437  *              bypass  add_tic_entry(), which now does its own "Tracing"
438  *              and Duplicate-Name functions on the new entry.
439  *
440  **************************************************************************** */
441 
create_split_alias(char * new_name,char * old_name,tic_hdr_t ** src_vocab,tic_hdr_t ** dest_vocab)442 bool create_split_alias( char *new_name, char *old_name,
443                               tic_hdr_t **src_vocab, tic_hdr_t **dest_vocab )
444 {
445     tic_hdr_t *found ;
446     bool retval = FALSE;
447 
448     found = lookup_tic_entry( old_name, *src_vocab );
449     if ( found != NULL )
450     {
451 	bool trace_it = found->tracing;
452 	if ( ! trace_it )
453 	{
454 	    trace_it = is_on_trace_list( new_name);
455 	}
456 	if ( trace_it )
457 	{
458 	    bool old_is_global = BOOLVAL( src_vocab != dest_vocab );
459 	    trace_creation( found, new_name, old_is_global);
460 	}
461 	warn_if_duplicate( new_name);
462 
463 	*dest_vocab = make_tic_entry( new_name,
464 			   found->funct,
465 			   found->pfield.deflt_elem,
466 				   found->fword_defr, 0,
467 			               found->is_token,
468 					   found->ign_func,
469 					       trace_it,
470 						   dest_vocab );
471 	retval = TRUE;
472     }
473 
474     return ( retval );
475 }
476 
477 /* **************************************************************************
478  *
479  *      Function name:  create_tic_alias
480  *      Synopsis:       Create an Alias in a TIC_HDR -type vocabulary
481  *                          Return a "success" flag.
482  *
483  *      Associated FORTH word:                 ALIAS
484  *
485  *      Inputs:
486  *         Parameters:
487  *             old_name             Name of existing entry
488  *             new_name             New name for which to create an entry
489  *             *tic_vocab           Pointer to the "tail" of the
490  *                                      T. I. C. -type vocab-list
491  *
492  *      Outputs:
493  *         Returned Value:          TRUE if  old_name  found in given vocab
494  *         Supplied Pointers:
495  *             *tic_vocab           Will be updated to point to the new entry
496  *         Memory Allocated:
497  *             For the new entry, by the support routine.
498  *         When Freed?
499  *             When reset_tic_vocab() is applied to the same vocab-list.
500  *
501  *      Process Explanation:
502  *          The given vocabulary is both the "Source" and the "Destination".
503  *              Pass them both to  create_split_alias.
504 
505  **************************************************************************** */
506 
create_tic_alias(char * new_name,char * old_name,tic_hdr_t ** tic_vocab)507 bool create_tic_alias( char *new_name, char *old_name, tic_hdr_t **tic_vocab )
508 {
509     return ( create_split_alias( new_name, old_name, tic_vocab, tic_vocab ) );
510 }
511 
512 
513 /* **************************************************************************
514  *
515  *      Function name:  handle_tic_vocab
516  *      Synopsis:       Perform the function associated with the given name
517  *                      in the given TIC_HDR -type vocabulary
518  *
519  *      Inputs:
520  *         Parameters:
521  *             tname                The "target" name for which to look
522  *             tic_vocab            Pointer to the T. I. C. -type vocabulary
523  *
524  *      Outputs:
525  *         Returned Value:   TRUE if the given name is valid in the given vocab
526  *         Global Variables:
527  *             tic_found            Points to the TIC entry of the "target"
528  *                                      name, if it was found; else, NULL.
529  *         Global Behavior:
530  *             Whatever the associated function does...
531  *
532  *      Process Explanation:
533  *          Find the name and execute its associated function.
534  *          If the name is not in the given vocabulary, return
535  *              an indication; leave it to the calling routine
536  *              to decide how to proceed.
537  *
538  **************************************************************************** */
539 
handle_tic_vocab(char * tname,tic_hdr_t * tic_vocab)540 bool handle_tic_vocab( char *tname, tic_hdr_t *tic_vocab )
541 {
542     bool retval = FALSE;
543 
544     tic_found = lookup_tic_entry( tname, tic_vocab );
545     if ( tic_found != NULL )
546     {
547         tic_found->funct( tic_found->pfield);
548 	retval = TRUE;
549     }
550 
551     return ( retval ) ;
552 }
553 
554 /* **************************************************************************
555  *
556  *      Function name:  reset_tic_vocab
557  *      Synopsis:       Reset a given TIC_HDR -type vocabulary to
558  *                          its given "Built-In" position.
559  *
560  *      Inputs:
561  *         Parameters:
562  *             *tic_vocab            Pointer to the T. I. C.-type vocab-list
563  *             reset_position        Position to which to reset the list
564  *
565  *      Outputs:
566  *         Returned Value:         NONE
567  *         Supplied Pointers:
568  *             *tic_vocab          Reset to given "Built-In" position.
569  *         Memory Freed
570  *             All memory allocated by user-definitions will be freed
571  *
572  *      Process Explanation:
573  *          The "stable memory-spaces" to which the name and parameter
574  *              field pointers point are presumed to have been acquired
575  *              by allocation of memory, which is reasonable for entries
576  *              created by the user as opposed to the built-in entries,
577  *              which we are, in any case, not releasing.
578  *          The parameter-field size field tells us whether we need to
579  *              free()  the parameter-field pointer.
580  *
581  **************************************************************************** */
582 
reset_tic_vocab(tic_hdr_t ** tic_vocab,tic_hdr_t * reset_position)583 void reset_tic_vocab( tic_hdr_t **tic_vocab, tic_hdr_t *reset_position )
584 {
585     tic_hdr_t *next_t;
586 
587     next_t = *tic_vocab;
588     while ( next_t != reset_position  )
589     {
590 	next_t = (*tic_vocab)->next ;
591 
592 	free( (*tic_vocab)->name );
593 	if ( (*tic_vocab)->pfld_size != 0 )
594 	{
595 	    free( (*tic_vocab)->pfield.chr_ptr );
596 	}
597 	free( *tic_vocab );
598 	*tic_vocab = next_t ;
599     }
600 }
601