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