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  *      Error-Handler for Tokenizer
28  *
29  *      Controls printing of various classes of errors
30  *
31  *      (C) Copyright 2005 IBM Corporation.  All Rights Reserved.
32  *      Module Author:  David L. Paktor    dlpaktor@us.ibm.com
33  *
34  **************************************************************************** */
35 
36 /* **************************************************************************
37  *
38  *      Functions Exported:
39  *          init_error_handler  Initialize the error-counts,
40  *                                  announce the file names.
41  *          tokenization_error  Handle an error of the given class,
42  *                                  print the given message in the
43  *                                  standard format.
44  *          started_at          Supplemental message, giving a back-reference
45  *                                  to the "starting"  point of a compound
46  *                                  error, including last-colon identification.
47  *          just_started_at     Supplemental back-reference to "starting"  point
48  *                                  of compound error, but without last-colon
49  *                                  identification.
50  *          where_started       Supplemental message, giving a more terse back-
51  *                                  -reference to "start" of compound-error.
52  *          just_where_started Supplemental message, more terse back-reference,
53  *                                  without last-colon identification.
54  *          in_last_colon      Supplemental back-reference message,
55  *                                  identifying last Colon-definition.
56  *          safe_malloc         malloc with built-in failure test.
57  *          error_summary       Summarize final error-message status
58  *                                  before completing tokenization.
59  *
60  **************************************************************************** */
61 
62 /* **************************************************************************
63  *
64  *      Revision History:
65  *          Updated Fri, 13 Oct 2006 by David L. Paktor
66  *          Added "(Output Position ..." to standard message format.
67  *
68  **************************************************************************** */
69 
70 
71 /* **************************************************************************
72  *
73  *          We will define a set of bit-valued error-types and a
74  *          global bit-mask.  Each error-message will be associated
75  *          with one of the bit-valued error-types.  The bit-mask,
76  *          which will be set by a combination of defaults and user
77  *          inputs (mainly command-line arguments), will control
78  *          whether an error-message of any given type is printed.
79  *
80  *          Another bit-mask variable will accumulate the error-
81  *          types that occur within any given run; at the end of
82  *          the run, it will be examined to determine if the run
83  *          failed, i.e., if the output should be suppressed.
84  *
85  **************************************************************************** */
86 
87 /* **************************************************************************
88  *
89  *          Error-types fall into the following broad categories:
90  *              FATAL           Cause to immediately stop activity
91  *              TKERROR         Sufficient to make the run a failure,
92  *                                  but not to stop activity.
93  *              WARNING         Not necessarily an error, but something
94  *                                  to avoid.  E.g., it might rely on
95  *                                  assumptions that are not necessarily
96  *                                  what the user/programmer wants.  Or:
97  *                                  It's a deprecated feature, or one
98  *                                  that might be incompatible with
99  *                                  other standard tokenizers.
100  *
101  *          Other types of Messages fall into these broad categories:
102  *              INFO            Nothing is changed in processing, but
103  *                                  an advisory is still in order.  Omitted
104  *                                  if "verbose" is not specified.
105  *              MESSAGE         Message generated by the user.  (Complete;
106  *                                  new-line will be added by display routine.)
107  *              P_MESSAGE       Partial Message -- Instigated by user, but
108  *                                  pre-formatted and not complete.  New-line
109  *                                  will be added by follow-up routine.
110  *              TRACER          Message related to the trace-symbols option;
111  *                                  either a creation or an invocation message.
112  *
113  **************************************************************************** */
114 
115 #include <stdio.h>
116 #include <stdarg.h>
117 #include <stdlib.h>
118 #include <string.h>
119 #include <errno.h>
120 
121 #include "types.h"
122 #include "toke.h"
123 #include "stream.h"
124 #include "emit.h"
125 #include "errhandler.h"
126 #include "scanner.h"
127 
128 /* **************************************************************************
129  *
130  *          Global Variables Imported
131  *              iname           Name of file currently being processed
132  *              lineno          Current line-number being processed
133  *              noerrors        "Ignore Errors" flag, set by "-i" switch
134  *              opc             FCode Output Buffer Position Counter
135  *              pci_hdr_end_ob_off
136  *                              Position in FCode Output Buffer of
137  *                                   end of last PCI Header Block structure
138  *              verbose         If true, enable Advisory Messages
139  *
140  **************************************************************************** */
141 
142 /* **************************************************************************
143  *
144  *              Internal Static Variables
145  *          print_msg               Whether beginning of a message was printed;
146  *                                      therefore, whether to print the rest.
147  *          errs_to_print           Error Verbosity Mask.  Bits set correspond
148  *                                      to message-types that will be printed
149  *                                      May be altered by Command-Line switches.
150  *          err_types_found         Accumulated Error-types.  Bits
151  *                                      set correspond to error-types
152  *                                      that have occurred.
153  *          message_dest            Message Dest'n.  Usually ERRMSG_DESTINATION
154  *                                      (stdout) except when we need to switch.
155  *          err_count               Count of Error Messages
156  *          warn_count              Count of Warning Messages
157  *          info_count              Count of "Advisory" Messages
158  *          user_msg_count          Count of User-generated Messages
159  *          trace_msg_count         Count of Trace-Note Messages
160  *          fatal_err_exit          Exit code to be used for "Fatal" error.
161  *                                       This is a special accommodation
162  *                                       for the  safe_malloc  routine.
163  *
164  **************************************************************************** */
165 
166 static bool  print_msg ;
167 static int errs_to_print = ( FATAL | TKERROR | WARNING |
168                              MESSAGE | P_MESSAGE | TRACER | FORCE_MSG ) ;
169 static int err_types_found =  0 ;
170 static int err_count       =  0 ;
171 static int warn_count      =  0 ;
172 static int info_count      =  0 ;
173 static int user_msg_count  =  0 ;
174 static int trace_msg_count =  0 ;
175 static int fatal_err_exit  = -1 ;
176 static FILE *message_dest;     /*  Would like to init to  ERRMSG_DESTINATION
177 				*      here, but the compiler complains...
178 				*/
179 
180 /* **************************************************************************
181  *
182  *              Internal Static Constant Structure
183  *          err_category            Correlate each error-type code with its
184  *                                      Counter-variable and the printable
185  *                                      form of its name.
186  *          num_categories          Number of entries in the err_category table
187  *
188  **************************************************************************** */
189 
190 typedef struct {
191     int  type_bit ;		/*  Error-type single-bit code        */
192     char *category_name ;	/*  Printable-name base               */
193     char *single ;		/*  Suffix to print singular of name  */
194     char *plural ;		/*  Suffix to print plural of name    */
195     int  *counter ;		/*  Associated Counter-variable       */
196     bool new_line ;		/*  Whether to print new-line at end  */
197 } err_category ;
198 
199 static const err_category  error_categories[] = {
200     /*  FATAL  must be the first entry in the table.   */
201     /*  No plural is needed; only one is allowed....   */
202     { FATAL,    "Fatal Error", "", "",     &err_count      , TRUE  },
203 
204     { TKERROR,    "Error"     , "", "s",    &err_count      , FALSE },
205     { WARNING,    "Warning"   , "", "s",    &warn_count     , FALSE },
206     { INFO,       "Advisor"   , "y", "ies", &info_count     , FALSE },
207     { MESSAGE ,   "Message"   , "", "s",    &user_msg_count , TRUE  },
208     { P_MESSAGE , "Message"   , "", "s",    &user_msg_count  , FALSE },
209     { TRACER , "Trace-Note"   , "", "s",    &trace_msg_count , FALSE }
210 };
211 
212 static const int num_categories =
213     ( sizeof(error_categories) / sizeof(err_category) );
214 
215 
216 /* **************************************************************************
217  *
218  *      Function name:  toup
219  *      Synopsis:       Support function for  strupper
220  *                      Converts one character
221  *
222  *      Inputs:
223  *         Parameters:
224  *             chr_ptr                 Pointer to the character
225  *
226  *      Outputs:
227  *         Returned Value:             None
228  *         Supplied Pointers:
229  *             The character pointed to is changed
230  *
231  *      Process Explanation:
232  *          Because this fills in a lack in the host system, we cannot
233  *              rely on the functions  islower  or  toupper , which are
234  *              usually built-in but might be similarly missing.
235  *
236  **************************************************************************** */
237 
toup(char * chr_ptr)238 static void toup( char *chr_ptr)
239 {
240     const unsigned char upcas_diff = ( 'a' - 'A' );
241     if ( ( *chr_ptr >= 'a' ) && ( *chr_ptr <= 'z' ) )
242     {
243 	*chr_ptr -= upcas_diff ;
244     }
245 }
246 
247 /* **************************************************************************
248  *
249  *      Function name:  strupper
250  *      Synopsis:       Replacement for  strupr  on systems that don't
251  *                      seem to have it.  A necessary hack.
252  *
253  *      Inputs:
254  *         Parameters:
255  *             strung              Pointer to the string to be changed
256  *
257  *      Outputs:
258  *         Returned Value:         Same pointer that was passed in
259  *         Supplied Pointers:
260  *             The string pointed to will be converted to upper case
261  *
262  *      Process Explanation:
263  *          Because it fills in a lack in the host system, this routine
264  *              does not rely on the functions  islower  or  toupper
265  *              which are usually built-in but might be missing.
266  *
267  **************************************************************************** */
268 
strupper(char * strung)269 char *strupper( char *strung)
270 {
271     char *strindx;
272     for (strindx = strung; *strindx != 0; strindx++)
273     {
274         toup( strindx);
275     }
276     return strung;
277 }
278 
279 /* **************************************************************************
280  *
281  *     If  strupr  is missing, it's a good bet that so is  strlwr
282  *
283  **************************************************************************** */
284 
285 /* **************************************************************************
286  *
287  *      Function name:  tolow
288  *      Synopsis:       Support function for  strlower
289  *                      Converts one character
290  *
291  *      Inputs:
292  *         Parameters:
293  *             chr_ptr                 Pointer to the character
294  *
295  *      Outputs:
296  *         Returned Value:             None
297  *         Supplied Pointers:
298  *             The character pointed to is changed
299  *
300  *      Process Explanation:
301  *          Because this fills in a lack in the host system, we cannot
302  *              rely on the functions  isupper  or  tolower , which are
303  *              usually built-in but might be similarly missing.
304  *
305  **************************************************************************** */
306 
tolow(char * chr_ptr)307 static void tolow( char *chr_ptr)
308 {
309     const unsigned char lowcas_diff = ( 'A' - 'a' );
310     if ( ( *chr_ptr >= 'A' ) && ( *chr_ptr <= 'Z' ) )
311     {
312 	*chr_ptr -= lowcas_diff ;
313     }
314 }
315 
316 /* **************************************************************************
317  *
318  *      Function name:  strlower
319  *      Synopsis:       Replacement for  strlwr  on systems that don't
320  *                      seem to have it.  A necessary hack.
321  *
322  *      Inputs:
323  *         Parameters:
324  *             strung              Pointer to the string to be changed
325  *
326  *      Outputs:
327  *         Returned Value:         Same pointer that was passed in
328  *         Supplied Pointers:
329  *             The string pointed to will be converted to lower case
330  *
331  *      Process Explanation:
332  *          Because it fills in a lack in the host system, this routine
333  *              does not rely on the functions  isupper  or  tolower
334  *              which are usually built-in but might be missing.
335  *
336  **************************************************************************** */
337 
strlower(char * strung)338 char *strlower( char *strung)
339 {
340     char *strindx;
341     for (strindx = strung; *strindx != 0; strindx++)
342     {
343         tolow( strindx);
344     }
345     return strung;
346 }
347 
348 
349 /* **************************************************************************
350  *
351  *      Function name:  init_error_handler
352  *      Synopsis:       Initialize the error-handler before starting a
353  *                          new tokenization; both the aspects that will
354  *                          persist across the entire run and those that
355  *                          need to be reset, such as error-counts.
356  *
357  *      Inputs:
358  *         Parameters:                 NONE
359  *         Global Variables:
360  *              verbose                Set by "-v" switch
361  *         Macro:
362  *             ERRMSG_DESTINATION      Error message destination;
363  *                                         (Set by development-time switch)
364  *             FFLUSH_STDOUT           Flush STDOUT if err-msg-dest is STDERR
365  *
366  *      Outputs:
367  *         Returned Value:             NONE
368  *         Global Variables:
369  *             errs_to_print           Add the INFO bit if verbose is set
370  *         Local Static Variables:
371  *             message_dest            Point it at ERRMSG_DESTINATION (stderr)
372  *           Reset the following to zero:
373  *             err_types_found         Accumulated Error-types.
374  *             err_count               Count of Error Messages
375  *             warn_count              Count of Warning Messages
376  *             info_count              Count of "Advisory" Messages
377  *             user_msg_count          Count of User-generated Messages
378  *             trace_msg_count         Count of Trace-Note Messages
379  *         Other Exotic Effects:
380  *             Flush stdout if Error message destination is not stdout, to
381  *                 avoid collisions with stderr once Error Messaging begins.
382  *
383  *      Extraneous Remarks:
384  *          This needs to be done before attempting to read the input file,
385  *              so that any Messages that occur there can be properly counted.
386  *
387  **************************************************************************** */
388 
init_error_handler(void)389 void init_error_handler( void)
390 {
391     int indx ;
392 
393     message_dest  =  ERRMSG_DESTINATION;
394     if ( verbose )  errs_to_print |= INFO ;
395     err_types_found = 0 ;
396 
397     /*  Start at indx = 1 to skip resetting FATALs   */
398     for ( indx = 1; indx < num_categories ; indx ++ )
399     {
400 	*(error_categories[indx].counter) = 0 ;
401     }
402 
403     FFLUSH_STDOUT
404 }
405 
406 /* **************************************************************************
407  *
408  *      Function name:    tokenization_error
409  *      Synopsis:         Handle an error of the given class,
410  *                            print the given message in the standard format.
411  *
412  *      Inputs:
413  *         Parameters:
414  *             err_type       int        One of the bit-valued error-types
415  *             The remaining parameters are a format string and corresponding
416  *                 data objects such as would be sent to  printf()
417  *         Global Variables:
418  *             errs_to_print        Error Verbosity Mask.
419  *             iname                Name of file currently being processed
420  *             lineno               Current line-number being processed
421  *             fatal_err_exit       Exit code for "Fatal" error, if applicable.
422  *             opc                  FCode Output Buffer Position Counter
423  *             pci_hdr_end_ob_off
424  *                                  Position in FCode Output Buffer of end
425  *                                       of last PCI Header Block structure
426 
427  *         Macro:
428  *             ERRMSG_DESTINATION        Error message destination;
429  *                                           (Development-time switch)
430  *         Note:  Whether this routine will or will not supply a new-line
431  *             at the end of the printout depends on the category of the
432  *             message.  The new-line is included for a FATAL or a User-
433  *             Generated Message, and excluded for the rest.  For those,
434  *             the calling routine must be responsible for including a
435  *             new-line at the end of the format string or for otherwise
436  *             finishing the line, as by calling started_at()
437  *
438  *      Outputs:
439  *         Returned Value:                 NONE
440  *         Local Static Variables:
441  *             err_types_found             Accumulated Error-types.
442  *             print_msg                   Whether this message was printed;
443  *                                             may be used by started_at()
444  *                    One of the following Category Counters
445  *                         will be incremented, as applicable:
446  *             err_count
447  *             warn_count
448  *             info_count
449  *             user_msg_count
450  *         Printout:    Directed to  stdout or stderr
451  *                          (see definition of ERRMSG_DESTINATION)
452  *
453  *      Error Detection:
454  *              Err_type not in list
455  *                      Print special message; treat cause as an Error.
456  *                      Force printout.
457  *
458  *      Process Explanation:
459  *          Accumulated the Error-type into  err_types_found
460  *          Identify the Error-Category:
461  *              Check the Error-Type against the bit-code.
462  *                  The Error-type may have more than one bit set,
463  *                  but if it matches the Category bit-code, it's it.
464  *              If it doesn't match any Error-Category bit-code, print
465  *                  a special message and treat it as an ERROR code.
466  *          Check the Error-Type against the Error Verbosity Mask;
467  *          If it has a bit set, print the Error-Category, together
468  *                  with the source-file name and line number, and
469  *                  the rest of the message as supplied.
470  *              The table that translates the Error-type into a printable
471  *                  Error-Category string also identifies the applicable
472  *                  Category Counter; increment it.
473  *          Of course, there's no return from a FATAL error; it exits.
474  *          The Message will show:
475  *              The Error-Category (always)
476  *              The Input File-name and Line Number (if input file was opened)
477  *              The Output Buffer Position (if output has begun)
478  *              The PCI-Block Position (if different from Output Buffer Pos'n)
479  *
480  **************************************************************************** */
481 
tokenization_error(int err_type,char * msg,...)482 void tokenization_error( int err_type, char* msg, ... )
483 {
484     int indx ;
485 
486     /*  Initial settings:  treat as an Error.  */
487     char *catgy_name = "Error";
488     char *catgy_suffx = "";
489     int *catgy_counter = &err_count;
490     bool print_new_line = FALSE;
491 
492     /*  Accumulated the Error-type into  err_types_found  */
493     err_types_found |= err_type;
494 
495     /*  Identify the Error-Category.  */
496     for ( indx = 0 ; indx < num_categories ; indx ++ )
497     {
498         if ( ( error_categories[indx].type_bit & err_type ) != 0 )
499         {
500             catgy_name = error_categories[indx].category_name;
501             catgy_suffx = error_categories[indx].single;
502             catgy_counter = error_categories[indx].counter;
503 	    print_new_line = error_categories[indx].new_line;
504             break;
505         }
506     }
507 
508     /*  Special message if  err_type  not in list; treat as an Error.  */
509     if ( catgy_name == NULL )
510     {
511          fprintf(ERRMSG_DESTINATION,
512 	      "Program error: Unknown Error-Type, 0x%08x.  "
513               "  Will treat as Error.\n", err_type) ;
514          err_types_found |= TKERROR;
515          print_msg = TRUE ;
516     } else {
517          /*  Check the Error-Type against the Error Verbosity Mask  */
518          print_msg = BOOLVAL( ( errs_to_print & err_type ) != 0 );
519     }
520 
521     if ( print_msg )
522     {
523         va_list argp;
524 
525 	fprintf(ERRMSG_DESTINATION, "%s%s:  ",
526              catgy_name, catgy_suffx);
527         if ( iname != NULL )
528 	{
529 	    /*  Don't print iname or lineno if no file opened.  */
530 	    fprintf(ERRMSG_DESTINATION, "File %s, Line %d.  ",
531         	 iname, lineno);
532 	}
533         if ( opc > 0 )
534 	{
535 	    /*  Don't print Output Position if no output started.  */
536 	    fprintf(ERRMSG_DESTINATION, "(Output Position = %d).  ", opc);
537 	}
538         if ( pci_hdr_end_ob_off > 0 )
539 	{
540 	    /*  Don't print PCI-Block Position if no PCI-Block in effect.  */
541 	    fprintf(ERRMSG_DESTINATION, "(PCI-Block Position = %d).  ",
542 	        opc - pci_hdr_end_ob_off );
543 	}
544 
545         va_start(argp, msg);
546         vfprintf(ERRMSG_DESTINATION, msg, argp);
547         va_end(argp);
548 	if ( print_new_line ) fprintf(ERRMSG_DESTINATION, "\n");
549 
550 	/*   Increment the category-counter.  */
551 	*catgy_counter += 1;
552     }
553     if ( err_type == FATAL )
554     {
555         fprintf(ERRMSG_DESTINATION, "Tokenization terminating.\n");
556         error_summary();
557         exit ( fatal_err_exit );
558     }
559 }
560 
561 /* **************************************************************************
562  *
563  *      Function name:  print_where_started
564  *      Synopsis:       Supplemental message, following a tokenization_error,
565  *                          giving a back-reference to the "start" point of
566  *                          the compound-error being reported.
567  *                      This is a retro-fit; it does the heavy lifting for
568  *                          the routines  started_at() ,  just_started_at() ,
569  *                           where_started() ,  just_where_started() and
570  *                           in_last_colon() .
571  *
572  *      Inputs:
573  *         Parameters:
574  *             show_started         Whether to print a phrase about "started"
575  *             show_that_st         Whether to print "that started" as opposed
576  *                                      to " , which started"
577  *             saved_ifile          File-name saved for "back-reference"
578  *             saved_lineno         Line-number saved for "back-reference"
579  *             may_show_incolon     Whether to allow a call to  in_last_colon()
580  *                                      Needed to prevent infinite recursion...
581  *         Global Variables:
582  *             iname                Name of file currently being processed
583  *             lineno               Current line-number being processed
584  *         Local Static Variables:
585  *             print_msg            Whether the beginning part of the message
586  *                                      was printed by tokenization_error()
587  *             message_dest         Message Destination. Is ERRMSG_DESTINATION
588  *                                      (stdout) usually, except sometimes...
589  *
590  *      Outputs:
591  *         Returned Value:          None
592  *         Printout:
593  *             The remainder of a message:  the location of a back-reference.
594  *                 The phrase "that started" is switchable.  This routine
595  *                 will supply the leading space and a new-line; the routines
596  *                 that call this can be used to finish the line.
597  *
598  *      Process Explanation:
599  *          This routine is called immediately after tokenization_error()
600  *              If tokenization_error() didn't print, neither will we.
601  *              The residual state of  print_msg  will tell us that.
602  *          If the preceding message ended with something general about a
603  *              "Colon Definition" or "Device-Node" or the like, we want
604  *              the message to read:  "that started on line ... [in file ...]"
605  *          If the end of the preceding message was something more specific,
606  *              we just want the message to read:  "on line ... [in file ...]"
607  *          If the saved input file name doesn't match our current input
608  *              file name, we will print it and the saved line-number.
609  *          If the file name hasn't changed, we will print only the saved
610  *              line-number.
611  *          If neither is changed, there's no point in printing any of the
612  *              above-mentioned text.
613  *          If a Colon-definition is in progress, show its name and the
614  *              line on which it started.  Protect against infinite loop!
615  *          End the line.
616  *
617  *      Extraneous Remarks:
618  *          This is a retrofit.  Earlier, it was just  started_at() .  Later,
619  *              I generated more specific messages, and needed a way to leave
620  *              out the "that started".  I could, theoretically, have added
621  *              the extra parameter to  started_at() , but by now there are
622  *              so many of calls to it that I'd rather leave them as is, and
623  *              just change the name of the routine in the few places that
624  *              need the terser form of the message.
625  *
626  **************************************************************************** */
627 
print_where_started(bool show_started,bool show_that_st,char * saved_ifile,unsigned int saved_lineno,bool may_show_incolon)628 static void print_where_started( bool show_started,
629                                    bool show_that_st,
630 				   char * saved_ifile,
631 				       unsigned int saved_lineno,
632                                            bool may_show_incolon)
633 {
634     if ( print_msg )
635     {
636 	bool fil_is_diff;
637 	bool lin_is_diff;
638 
639 	/*  File names are case-sensitive  */
640 	fil_is_diff = BOOLVAL(strcmp(saved_ifile, iname) != 0 );
641 	lin_is_diff = BOOLVAL(saved_lineno != lineno );
642 	if ( fil_is_diff || lin_is_diff )
643 	{
644 	    if ( show_started )
645 	    {
646 		if ( show_that_st )
647 		{
648 		    fprintf(message_dest, " that");
649 		}else{
650 		    fprintf(message_dest, " , which");
651 		}
652 		fprintf(message_dest, " started");
653 	    }
654 	    fprintf(message_dest, " on line %d", saved_lineno);
655 	    if ( fil_is_diff )
656 	    {
657 	        fprintf(message_dest, " of file %s", saved_ifile);
658 	    }
659 	}
660 
661 	if ( may_show_incolon )
662 	{
663 	    in_last_colon( TRUE );
664 	}else{
665 	    fprintf(message_dest, "\n");
666 	}
667     }
668 }
669 
670 /* **************************************************************************
671  *
672  *      Function name:  started_at
673  *      Synopsis:       Supplemental back-reference message,
674  *                          with the "that started"  phrase,
675  *                          and with last-colon identification.
676  *
677  *      Inputs:
678  *         Parameters:
679  *             saved_ifile          File-name saved for "back-reference"
680  *             saved_lineno         Line-number saved for "back-reference"
681  *
682  *      Outputs:
683  *         Returned Value:          None
684  *         Global Variables:
685  *         Printout:
686  *             The "...started at..." remainder of a message, giving a back-
687  *                 -reference to the  "start" point supplied in the params,
688  *                 and the start of the current Colon-definition if one is
689  *                 in effect.
690  *             Will supply a new-line and can be used to finish the line.
691  *
692  **************************************************************************** */
693 
started_at(char * saved_ifile,unsigned int saved_lineno)694 void started_at( char * saved_ifile, unsigned int saved_lineno)
695 {
696     print_where_started( TRUE, TRUE, saved_ifile, saved_lineno, TRUE);
697 }
698 
699 
700 /* **************************************************************************
701  *
702  *      Function name:  print_started_at
703  *      Synopsis:       Same as started_at() except output will be directed
704  *                          to  stdout  instead of to ERRMSG_DESTINATION
705  *
706  *      Extraneous Remarks:
707  *          A retrofit.  Can you tell?
708  *
709  **************************************************************************** */
710 
print_started_at(char * saved_ifile,unsigned int saved_lineno)711 void print_started_at( char * saved_ifile, unsigned int saved_lineno)
712 {
713     message_dest = stdout;
714 	started_at( saved_ifile, saved_lineno);
715     message_dest = ERRMSG_DESTINATION;
716 }
717 
718 
719 /* **************************************************************************
720  *
721  *      Function name:  just_started_at
722  *      Synopsis:       Supplemental back-reference message,
723  *                          with the "that started"  phrase,
724  *                          but without last-colon identification.
725  *
726  *      Inputs:
727  *         Parameters:
728  *             saved_ifile          File-name saved for "back-reference"
729  *             saved_lineno         Line-number saved for "back-reference"
730  *
731  *      Outputs:
732  *         Returned Value:          None
733  *         Global Variables:
734  *         Printout:
735  *             The "...started at..." remainder of a message, giving a back-
736  *                 -reference to the  "start" point supplied in the params,
737  *                 and no more.
738  *             Will supply a new-line and can be used to finish the line.
739  *
740  **************************************************************************** */
741 
just_started_at(char * saved_ifile,unsigned int saved_lineno)742 void just_started_at( char * saved_ifile, unsigned int saved_lineno)
743 {
744     print_where_started( TRUE, TRUE, saved_ifile, saved_lineno, FALSE);
745 }
746 
747 /* **************************************************************************
748  *
749  *      Function name:  where_started
750  *      Synopsis:       Supplemental back-reference message,
751  *                          without the "that started"  phrase,
752  *                          but with last-colon identification.
753  *
754  *      Inputs:
755  *         Parameters:
756  *             saved_ifile          File-name saved for "back-reference"
757  *             saved_lineno         Line-number saved for "back-reference"
758  *
759  *      Outputs:
760  *         Returned Value:          None
761  *         Global Variables:
762  *         Printout:
763  *             The remainder of a message, giving a back-reference to the
764  *                 "start" point supplied in the parameters, and the start
765  *                 of the current Colon-definition if one is in effect.
766  *             Will supply a new-line and can be used to finish the line.
767  *
768  **************************************************************************** */
769 
where_started(char * saved_ifile,unsigned int saved_lineno)770 void where_started( char * saved_ifile, unsigned int saved_lineno)
771 {
772     print_where_started( FALSE, FALSE, saved_ifile, saved_lineno, TRUE);
773 }
774 
775 /* **************************************************************************
776  *
777  *      Function name:  just_where_started
778  *      Synopsis:       Supplemental back-reference message,
779  *                          without the "that started"  phrase,
780  *                          and without last-colon identification.
781  *
782  *      Inputs:
783  *         Parameters:
784  *             saved_ifile          File-name saved for "back-reference"
785  *             saved_lineno         Line-number saved for "back-reference"
786  *
787  *      Outputs:
788  *         Returned Value:          None
789  *         Global Variables:
790  *         Printout:
791  *             The remainder of a message, giving a back-reference to the
792  *                 "start" point supplied in the parameters, and no more.
793  *             Will supply a new-line and can be used to finish the line.
794  *
795  **************************************************************************** */
796 
just_where_started(char * saved_ifile,unsigned int saved_lineno)797 void just_where_started( char * saved_ifile, unsigned int saved_lineno)
798 {
799     print_where_started( FALSE, FALSE, saved_ifile, saved_lineno, FALSE);
800 }
801 
802 /* **************************************************************************
803  *
804  *      Function name:  in_last_colon
805  *      Synopsis:       Supplemental back-reference message, identifying
806  *                          last Colon-definition if one is in effect.
807  *                      Can be used to finish the line in either case.
808  *
809  *      Inputs:
810  *         Parameters:
811  *             say_in                    If TRUE, lead phrase with " in ".
812  *                                           If FALSE, print even if not
813  *                                            inside a Colon-def'n.
814  *         Global Variables:
815  *             incolon                   TRUE if Colon-definition is in progress
816  *             last_colon_defname        Name of last colon-definition
817  *             last_colon_filename       File where last colon-def'n made
818  *             last_colon_lineno         Line number of last colon-def'n
819  *         Local Static Variables:
820  *             print_msg            Whether the beginning part of the message
821  *                                      was printed by tokenization_error()
822  *             message_dest         Message Destination. Is ERRMSG_DESTINATION
823  *                                      (stdout) usually, except sometimes...
824  *
825  *      Outputs:
826  *         Returned Value:                  NONE
827  *         Printout:
828  *             Remainder of a message:
829  *                "in definition of  ... , which started ..."
830  *
831  *      Process Explanation:
832  *          Because this routine does some of its own printing, it needs
833  *              to check the residual state of  print_msg  first.
834  *          The calling routine does not need to test   incolon ; it can
835  *              call this (with TRUE) to end the line in either case.
836  *
837  **************************************************************************** */
838 
in_last_colon(bool say_in)839 void in_last_colon( bool say_in )
840 {
841     if ( print_msg )
842     {
843 	if ( incolon || ( ! say_in ) )
844 	{
845 	    fprintf( message_dest, "%s definition of  %s ", say_in ? " in" : "",
846 		strupr( last_colon_defname) );
847 	    print_where_started( TRUE, FALSE,
848 		last_colon_filename, last_colon_lineno, FALSE);
849 	}else{
850 	    fprintf(message_dest, "\n");
851 	}
852     }
853 }
854 
855 
856 /* **************************************************************************
857  *
858  *      Function name:  safe_malloc
859  *      Synopsis:       malloc with built-in failure test.
860  *
861  *      Inputs:
862  *         Parameters:
863  *             size       size_t     Size of memory-chunk to allocate
864  *             phrase     char *     Phrase to print after "... while "
865  *                                       in case of failure.
866  *
867  *      Outputs:
868  *         Returned Value:           Pointer to allocated memory
869  *         Global Variables:
870  *             fatal_err_exit       On memory allocation failure, change
871  *                                       to a special system-defined value
872  *
873  *      Error Detection:
874  *          On memory allocation failure, declare a FATAL error.  Set up
875  *              for a special system-defined EXIT value that indicates
876  *              insufficient memory.
877  *
878  *      Process Explanation:
879  *          It is the responsibility of the calling routine to be sure
880  *              the "phrase" is unique within the program.  It is intended
881  *              as a debugging aid, to help localize the point of failure.
882  *
883  **************************************************************************** */
884 
safe_malloc(size_t size,char * phrase)885 _PTR safe_malloc( size_t size, char *phrase)
886 {
887     _PTR retval ;
888     retval = malloc (size);
889     if ( !retval )
890     {
891         fatal_err_exit = -ENOMEM ;
892         tokenization_error( FATAL, "Out of memory while %s.", phrase);
893     }
894     return ( retval );
895 }
896 
897 /* **************************************************************************
898  *
899  *      Function name:         error_summary
900  *      Synopsis:              Summarize final error-message status
901  *                                 before completing tokenization.
902  *                             Indicate if OK to produce output.
903  *
904  *      Inputs:
905  *         Parameters:                   NONE
906  *         Global Variables:
907  *             noerrors             "Ignore Errors" flag, set by "-i" switch
908  *             err_types_found      Accumulated Error-types.
909  *             error_categories     Table of Error-types, Message-Counters
910  *                                      and their printable names.
911  *             opc                  FCode Output Buffer Position Counter
912  *                                      (zero means there was no output).
913  *
914  *      Outputs:
915  *         Returned Value:          True = OK to produce output (But caller
916  *                                      must still verify non-zero opc)
917  *         Printout:
918  *             Various messages.
919  *
920  *      Process Explanation:
921  *          The first entry in the error_categories table is FATAL
922  *              We won't need to print a tally of that...
923  *
924  **************************************************************************** */
925 
error_summary(void)926 bool error_summary( void )
927 {
928     /*  Bit-mask of error-types that require suppressing output   */
929     static const int suppress_mask = ( FATAL | TKERROR );
930     bool retval = TRUE;
931     bool suppressing = FALSE;
932 
933     /*  There's no escaping a FATAL error   */
934     if ( ( err_types_found & FATAL ) != 0 )
935     {
936 	/*   FATAL error.  Don't even bother with the tally.   */
937 	suppressing = TRUE;
938     } else {
939 
940 	if ( opc == 0 )
941 	{
942 	    printf ( "Nothing Tokenized");
943 	}else{
944 	    printf ( "Tokenization Completed");
945 	}
946 
947 	if ( err_types_found != 0 )
948 	{
949 	    int indx;
950 	    bool tally_started = FALSE ;
951 	    printf (". ");
952 	    /*
953 	     *  Print a tally of the error-types;
954 	     *  handle plurals and punctuation appropriately.
955 	     */
956 	    /*  Start at indx = 1 to skip examining FATALs   */
957 	    for ( indx = 1; indx < num_categories ; indx ++ )
958 	    {
959 		if ( *(error_categories[indx].counter) > 0 )
960 		{
961 		    printf ("%s %d %s%s",
962 	        	tally_started ? "," : "" ,
963 			    *(error_categories[indx].counter),
964 				error_categories[indx].category_name,
965 				    *(error_categories[indx].counter) > 1 ?
966 					 error_categories[indx].plural :
967 					     error_categories[indx].single );
968 		    /*  Zero out the counter, to prevent displaying the
969 		     *      number of Messages twice, since it's shared
970 		     *      by the "Messages" and "P_Messages" categories.
971 		     */
972 		    *(error_categories[indx].counter) = 0;
973 		    tally_started = TRUE;
974 		}
975 	    }
976 	}
977         printf (".\n");
978 
979 	if ( ( err_types_found & suppress_mask ) != 0 )
980 	{    /*  Errors found.  Not  OK to produce output    */
981              /*  Unless "Ignore Errors" flag set...          */
982 	    if ( INVERSE(noerrors) )
983             {
984 		suppressing = TRUE;
985             }else{
986 		if ( opc > 0 )
987 		{
988 		    printf ("Error-detection over-ridden; "
989 				"producing binary output.\n");
990 		}
991             }
992 	}
993     }
994     if ( suppressing )
995     {
996 	retval = FALSE ;
997 	printf ("Suppressing binary output.\n");
998     }
999     return ( retval );
1000 }
1001 
1002