1/*
2 * Copyright (c) 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1.  Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 * 2.  Redistributions in binary form must reproduce the above copyright
13 *     notice, this list of conditions and the following disclaimer in the
14 *     documentation and/or other materials provided with the distribution.
15 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
16 *     contributors may be used to endorse or promote products derived from
17 *     this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Portions of this software have been released under the following terms:
31 *
32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC.
33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY
34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION
35 *
36 * To anyone who acknowledges that this file is provided "AS IS"
37 * without any express or implied warranty:
38 * permission to use, copy, modify, and distribute this file for any
39 * purpose is hereby granted without fee, provided that the above
40 * copyright notices and this notice appears in all source code copies,
41 * and that none of the names of Open Software Foundation, Inc., Hewlett-
42 * Packard Company or Digital Equipment Corporation be used
43 * in advertising or publicity pertaining to distribution of the software
44 * without specific, written prior permission.  Neither Open Software
45 * Foundation, Inc., Hewlett-Packard Company nor Digital
46 * Equipment Corporation makes any representations about the suitability
47 * of this software for any purpose.
48 *
49 * Copyright (c) 2007, Novell, Inc. All rights reserved.
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions
52 * are met:
53 *
54 * 1.  Redistributions of source code must retain the above copyright
55 *     notice, this list of conditions and the following disclaimer.
56 * 2.  Redistributions in binary form must reproduce the above copyright
57 *     notice, this list of conditions and the following disclaimer in the
58 *     documentation and/or other materials provided with the distribution.
59 * 3.  Neither the name of Novell Inc. nor the names of its contributors
60 *     may be used to endorse or promote products derived from this
61 *     this software without specific prior written permission.
62 *
63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
73 *
74 * @APPLE_LICENSE_HEADER_END@
75 */
76
77/*
78**
79**  NAME
80**
81**      ERRORS.C
82**
83**  FACILITY:
84**
85**      Interface Definition Language (IDL) Compiler
86**
87**  ABSTRACT:
88**
89**      IDL Error logging and reporting routines.
90**
91**  VERSION: DCE 1.0
92**
93*/
94
95#include <nidl.h>
96#include <errors.h>
97#include <nametbl.h>
98#include <frontend.h>
99#include <message.h>
100#include <nidlmsg.h>
101#include <driver.h>
102#include <nidl.h>
103#include <stdarg.h>
104
105#define MAX_LINE_LEN    256
106#define WHERE_TEXT_LEN   20
107#define MAX_WARNINGS    5
108#define MAX_ERROR_FILES 10
109
110
111/*
112 *  Error log record format.
113 */
114typedef struct error_log_rec_t
115{
116    STRTAB_str_t     filename;  /* Error file name */
117    int              lineno;    /* Source line number */
118    idl_error_list_t msgs;      /* msgid + args */
119    union                       /* Tree node or List node */
120    {
121        struct
122        {                                   /* As tree node: */
123            struct  error_log_rec_t *left;  /* Left pointer */
124            struct  error_log_rec_t *right; /* Right pointer */
125        } asBinTree;
126        struct
127        {                                   /* As list node: */
128            struct  error_log_rec_t *next;  /* Ptr to next for this lineno */
129        } asList;
130    } links;
131    struct  error_log_rec_t *first_this_line;   /* 1st addtl msg this line */
132    struct  error_log_rec_t *last_this_line;    /* last addtl msg this line */
133} error_log_rec_t;
134
135/* Pointers to IDL parser or ACF parser global variables. */
136
137FILE    *yyin_p;           /* Points to yyin or acf_yyin */
138unsigned*yylineno_p;       /* Points to yylineno or acf_yylineno */
139
140boolean ERR_no_warnings;    /* Global copy of -no_warn command line option */
141
142static  int              warnings = 0;      /* Warning count */
143static  STRTAB_str_t    error_files[MAX_ERROR_FILES]; /* List of all files with errors */
144static  int     error_file_count = 0;       /* Number of files with errors */
145static  int     last_error_line = 0;        /* Line of last error */
146
147#if !YYDEBUG
148static
149#endif
150char const *current_file   = NULL;     /* Current source file name */
151
152error_log_rec_t  *errors = NULL;    /* Tree root for error nodes */
153int     error_count     = 0;        /* Error count */
154static STRTAB_str_t error_file_name_id; /* Id of current source file */
155
156extern void sysdep_cleanup_temp ( void );
157
158/*
159 *  y y w h e r e
160 *
161 *  Function:   Returns current input position for yyparse.
162 *
163 *  Globals:    yy*_p
164 *
165 */
166
167void yywhere
168(
169    const struct parser_location_t * location
170)
171{
172	boolean    have_text = false;  /* True if have source text to output */
173	int        text_len = 0;       /* Length of source text to output */
174	int        lineno;             /* Source line number of relevant text */
175	long       msg_id;             /* ID of message to output */
176	char const *near_text;         /* Text of object near error */
177	STRTAB_str_t string_id;     /* Entry in string table of near text */
178	char wherebuf[WHERE_TEXT_LEN+1];
179	const char * text_p;
180
181	text_p = location->text;
182	lineno = location->lineno;
183	error_file_name_id = location->fileid;
184
185	if (text_p && *text_p)
186	{
187		for (text_len = 0; text_len < WHERE_TEXT_LEN; ++text_len)
188		{
189			if (text_p[text_len] == '\0' || text_p[text_len] == '\n')
190				break;
191			wherebuf[text_len] = text_p[text_len];
192		}
193		wherebuf[text_len] = '\0';
194
195		if (text_len > 0)
196		{
197			have_text = true;
198			lineno = lineno - (*text_p == '\n' || ! *text_p);
199		}
200	/*	printf("wherebuf is %s, yytext has %s\n", wherebuf, *yytext_p); */
201	}
202
203	/*
204	 * If there is some text to show, put it in the string table
205	 */
206	if (have_text)
207	{
208		string_id = STRTAB_add_string(wherebuf);
209		STRTAB_str_to_string(string_id, &near_text);
210	}
211
212	if (have_text)
213	{
214		if (yyin_p && feof(yyin_p))
215			msg_id = NIDL_EOFNEAR;
216		else
217			msg_id = NIDL_SYNTAXNEAR;
218	}
219	else
220	{
221		if (yyin_p && feof(yyin_p))
222			msg_id = NIDL_EOF;
223		else
224			msg_id = NIDL_SYNTAXERR;
225	}
226	log_error(lineno, msg_id, text_len, near_text, NULL);
227}
228
229/*
230 *  i d l _ y y e r r o r
231 *
232 *  Function:   Called by yypaser when a parse error is encountered.
233 *
234 *  Inputs:     message -  error message to display
235 *              token    - expected token
236 *
237 *  Globals:
238 *
239 *  Notes:      This was adapted from the book
240 *                  "Compiler Construction under Unix"
241 *              by A. T. Schreiner & H. G. Friedman
242 */
243
244void idl_yyerror
245(
246	parser_location_p location,
247    char const * message
248)
249{
250    static int list = 0;        /* Note: Currently always 0 */
251
252    if (message || !list)
253    {
254		error_count++;
255        yywhere(location);
256
257        /*
258         * Only print the yacc version of errors if it isn't for a syntax error.
259         */
260        if (strcmp(message,"syntax error") != 0)
261        {
262            fputs(message, stderr);
263            putc('\n', stderr);
264            return;
265        }
266
267        return;
268    }
269
270    putc('\n', stderr);
271    list = 0;
272}
273
274
275/*
276 *  a l l o c _ l o g _ r e c
277 *
278 *  Function:   Allocates and initializes error log record.
279 *
280 *  Inputs:     lineno - source line number
281 *              message - message text
282 *
283 *  Outputs:    Address of error log record.
284 */
285
286static error_log_rec_t *alloc_log_rec
287(
288    STRTAB_str_t filename,
289    int  lineno,
290    idl_error_list_t *msgs
291)
292{
293    error_log_rec_t *log_rec_p;
294    int             i;
295
296    log_rec_p = NEW (error_log_rec_t);
297
298    log_rec_p->lineno  = lineno;
299    log_rec_p->filename = filename;
300    log_rec_p->msgs = *msgs;
301    log_rec_p->first_this_line = 0;
302    log_rec_p->last_this_line  = 0;
303
304    log_rec_p->links.asBinTree.left  = 0;
305    log_rec_p->links.asBinTree.right = 0;
306
307    log_rec_p->links.asList.next     = 0;
308
309    /*
310     * If this file is not listed in the error file list
311     */
312    for (i = 0; i < error_file_count; i++)
313        if (error_files[i] == filename)
314	    break;
315
316    /*
317     * Add the file with errors to the error_file list
318     */
319    if (i == error_file_count)
320        error_files[error_file_count++] = filename;
321
322    /*
323     * If we have too many files with errors, just ignore some
324     */
325    if (error_file_count >= MAX_ERROR_FILES)
326	error_file_count--;
327
328    return  log_rec_p;
329}
330
331/*
332 *  f r e e _ l o g _ r e c
333 *
334 *  Function:   Frees an error log record and anything below it
335 *
336 *  Inputs:     record - error log record to free
337 *  Outputs:    none
338 */
339
340static void free_log_rec
341(
342    error_log_rec_t *log_rec_p
343)
344{
345    if (log_rec_p->links.asBinTree.left  != NULL)
346    {
347        free_log_rec(log_rec_p->links.asBinTree.left);
348        log_rec_p->links.asBinTree.left = NULL;
349    }
350
351    if (log_rec_p->links.asBinTree.right  != NULL)
352    {
353        free_log_rec(log_rec_p->links.asBinTree.right);
354        log_rec_p->links.asBinTree.right = NULL;
355    }
356
357    /*
358     * Free all errors logged for this line number
359     */
360    while (log_rec_p->first_this_line != NULL)
361    {
362        error_log_rec_t *ep;
363        ep = log_rec_p->first_this_line;
364        log_rec_p->first_this_line = log_rec_p->links.asList.next;
365        FREE(ep);
366    }
367
368    FREE(log_rec_p);
369}
370
371/*
372 *  q u e u e _ e r r o r
373 *
374 *  Function:   Adds an error message to the end of a list of
375 *              errors queued for a particular line.
376 *
377 *  Inputs:     log_rec_p - a pointer to the header error log rec.
378 *              message   - the error message.
379 */
380
381static void queue_error
382(
383    error_log_rec_t  *log_rec_p,
384    STRTAB_str_t     filename,
385    idl_error_list_t *msgs
386)
387{
388    error_log_rec_t *new_log_rec_p;
389
390    new_log_rec_p = alloc_log_rec(filename, log_rec_p->lineno, msgs);
391
392    if (log_rec_p->first_this_line == NULL)
393    {
394        log_rec_p->first_this_line = new_log_rec_p;
395        log_rec_p->last_this_line  = new_log_rec_p;
396        return;
397    }
398
399    log_rec_p->last_this_line->links.asList.next = new_log_rec_p;
400    log_rec_p->last_this_line                    = new_log_rec_p;
401}
402
403/*
404 *  a d d _ e r r o r _ l o g _ r e c
405 *
406 *  Function:   Adds an error log to the sorted binary tree of
407 *              error messages.
408 *
409 *  Inputs:     log_rec_p - pointer to current root of tree.
410 *              lineno    - line number on which error occurred.
411 *              message   - the error message.
412 */
413
414static void add_error_log_rec
415(
416    error_log_rec_t *log_rec_p,
417    STRTAB_str_t filename,
418    int lineno,
419    idl_error_list_t *msgs
420)
421{
422    if (log_rec_p->lineno < lineno)
423    {
424        if (log_rec_p->links.asBinTree.right != NULL)
425            add_error_log_rec(log_rec_p->links.asBinTree.right, filename, lineno,
426                    msgs);
427        else
428            log_rec_p->links.asBinTree.right = alloc_log_rec(filename, lineno,
429                    msgs);
430
431        return;
432    }
433
434    if (log_rec_p->lineno > lineno)
435    {
436        if (log_rec_p->links.asBinTree.left != NULL)
437            add_error_log_rec(log_rec_p->links.asBinTree.left, filename, lineno,
438                    msgs);
439
440        else
441            log_rec_p->links.asBinTree.left = alloc_log_rec(filename, lineno,
442                    msgs);
443        return;
444    }
445
446    if (log_rec_p->lineno == lineno)
447	queue_error(log_rec_p, filename, msgs);
448}
449
450/*
451 *  l o g _ s o u r c e _ v a
452 *
453 *  Function:   Accumulates a warning or error message for later printout.
454 *              All accumulated errors are printed by print_errors.
455 *              Errors are kept sorted by line number and source
456 *              file name.
457 *
458 *  Inputs:
459 *              counter - which counter should be increased (error/warning)
460 *              filename - STRTAB_str_t of full source file name
461 *              lineno  - the line number of the error.
462 *              msg_id - the error message ID.
463 *              ap - va_list for the parameter last must be NULL if # < IDL_ERROR_LIST_SIZE
464 *
465 *  Outputs:    An error log record is inserted in the error tree.
466 *
467 */
468
469static void log_source_va
470(
471 int*         counter,
472 STRTAB_str_t filename,
473 int          lineno,
474 long         msg_id,
475 va_list      ap
476)
477{
478    idl_error_list_t msgs = {0, {NULL}};
479
480    size_t  idx;
481
482    ++*counter;
483
484    msgs.msg_id = msg_id;
485    for (idx = 0; idx < IDL_ERROR_LIST_SIZE; idx++) {
486	msgs.arg[idx] = va_arg(ap, void*);
487	if (!msgs.arg[idx])
488	    break;
489    }
490
491    if (errors == NULL)
492	errors = alloc_log_rec(filename, lineno, &msgs);
493    else
494	add_error_log_rec(errors, filename, lineno, &msgs);
495}
496
497
498/*
499 *  l o g _ s o u r c e _ e r r o r
500 *
501 *  Function:   Accumulates an error message for later printout.
502 *              All accumulated errors are printed by print_errors.
503 *              Errors are kept sorted by line number and source
504 *              file name.
505 *
506 *  Inputs:
507 *              filename - STRTAB_str_t of full source file name
508 *              lineno  - the line number of the error.
509 *              msg_id - the error message ID.
510 *              [arg1,...,arg5] - 0 to 5 arguments for error message formatting
511 *
512 *  Outputs:    An error log record is inserted in the error tree.
513 *
514 */
515
516void vlog_source_error
517(
518 STRTAB_str_t filename,
519 int lineno,
520 long msg_id,
521 va_list ap
522 )
523{
524    log_source_va(&error_count, filename, lineno, msg_id, ap);
525}
526
527void log_source_error
528(
529    STRTAB_str_t filename,
530    int lineno,
531    long msg_id,
532    ...
533)
534{
535    va_list ap;
536
537    va_start(ap, msg_id);
538
539    vlog_source_error(filename, lineno, msg_id, ap);
540
541    va_end(ap);
542}
543
544/*
545 *  l o g _ s o u r c e _ w a r n i n g
546 *
547 *  Function:   Accumulates a warning message for later printout.
548 *              All accumulated errors are printed by print_errors.
549 *              Errors are kept sorted by line number and source
550 *              file name.
551 *
552 *  Inputs:
553 *              filename - STRTAB_str_t of full source file name
554 *              lineno  - the line number of the error.
555 *              msg_id - the error message ID.
556 *              [arg1,...,arg5] - 0 to 5 arguments for error message formatting
557 *
558 *  Outputs:    An error log record is inserted in the error tree.
559 *
560 */
561void vlog_source_warning
562(
563 STRTAB_str_t filename,
564 int lineno,
565 long msg_id,
566 va_list ap
567)
568{
569    /* Return if warnings are suppressed. */
570    if (ERR_no_warnings)
571		return;
572
573    log_source_va(&warnings, filename, lineno, msg_id, ap);
574}
575
576void log_source_warning
577(
578    STRTAB_str_t filename,
579    int lineno,
580    long msg_id,
581    ...
582)
583{
584    va_list ap;
585
586    /* Return if warnings are suppressed. */
587    if (ERR_no_warnings)
588	return;
589
590    va_start(ap, msg_id);
591
592    vlog_source_warning(filename, lineno, msg_id, ap);
593
594    va_end(ap);
595}
596
597/*
598 *  l o g _ e r r o r
599 *
600 *  Function:   Accumulates an error message for later printout.
601 *              All accumulated errors are printed by print_errors.
602 *              Errors are kept sorted by line number.  The error
603 *              is logged on the file for which set_name_for_errors
604 *              was most recently called.
605 *
606 *  Inputs:     lineno  - the line number of the error.
607 *              msg_id - the error message ID.
608 *              [arg1,...,arg5] - 0 to 5 arguments for error message formatting
609 *
610 *  Outputs:    An error log record is inserted in the error tree.
611 *
612 */
613void vlog_error
614(
615 int lineno,
616 long msg_id,
617 va_list ap
618)
619{
620    log_source_va(&error_count, error_file_name_id, lineno, msg_id, ap);
621}
622
623void log_error
624(
625    int lineno,
626    long msg_id,
627    ...
628)
629{
630    va_list ap;
631
632    va_start(ap, msg_id);
633
634    vlog_error(lineno, msg_id, ap);
635
636    va_end(ap);
637}
638
639
640/*
641 *  l o g _ w a r n i n g
642 *
643 *  Function:   Accumulates a warning message for later printout.
644 *              All accumulated errors are printed by print_errors.
645 *              Errors are kept sorted by line number.  The warning
646 *              is logged on the file for which set_name_for_errors
647 *              was most recently called.
648 *
649 *  Inputs:     lineno  - the line number of the warning.
650 *              msg_id - the error message ID.
651 *              [arg1,...,arg5] - 0 to 5 arguments for error message formatting
652 *
653 *  Outputs:    An error log record is inserted in the error tree.
654 *
655 */
656void vlog_warning
657(
658 int lineno,
659 long msg_id,
660 va_list ap
661)
662{
663    if (ERR_no_warnings)
664		return;
665
666    log_source_va(&warnings, error_file_name_id, lineno, msg_id, ap);
667}
668
669void log_warning
670(
671    int lineno,
672    long msg_id,
673    ...
674)
675{
676    va_list ap;
677
678    if (ERR_no_warnings)
679	return;
680    va_start(ap, msg_id);
681
682    vlog_warning(lineno, msg_id, ap);
683
684    va_end(ap);
685}
686
687
688/*
689 *  s e e k _ f o r _ l i n e
690 *
691 *  Function:   Reads the line specified by lineno.
692 *
693 *  Inputs:     source - the file descriptor for the source file.
694 *              lineno - the number of the line in error.
695 *
696 *  Outputs:    source_line - the source line is returned through here
697 *
698 *  Globals:    last_error_line
699 */
700
701void seek_for_line
702(
703    FILE *source_file,
704    int lineno,
705    char *source_line
706)
707{
708    int lines_to_skip;
709    int i;
710
711    /*
712     * If the FILE is NULL then can't get the source
713     */
714    if (source_file == NULL)
715    {
716        source_line[0] = 0;
717        return;
718    }
719
720    lines_to_skip = lineno - last_error_line;
721
722    for (i=0; i<lines_to_skip; i++)
723        (void) fgets(source_line, MAX_LINE_LEN, source_file);
724
725    /* Strip off newline. */
726    i = strlen(source_line) - 1;
727    if (source_line[i] == '\n')
728        source_line[i] = '\0';
729
730    last_error_line = lineno;
731}
732
733/*
734 *  p r i n t _ e r r o r s _ f o r _ l i n e
735 *
736 *  Function:   Prints out a source line and accumulated errors
737 *              for that line.
738 *
739 *  Inputs:     fd - file descriptor for source file
740 *              log_rec_ptr - a pointer to the header log rec for the line
741 *              source - source file name
742 */
743
744void print_errors_for_line
745(
746    FILE *fd,
747    char const *source,
748    STRTAB_str_t    source_id,
749    error_log_rec_t *log_rec_ptr
750)
751{
752    char            source_line[MAX_LINE_LEN];
753    boolean         source_printed = false;
754    error_log_rec_t *erp;
755
756    /* Print the error only if it in this file */
757    if (source_id == log_rec_ptr->filename)
758    {
759        source_printed = true;
760        seek_for_line(fd, log_rec_ptr->lineno, source_line);
761        message_print(
762            NIDL_FILESOURCE, source, log_rec_ptr->lineno, source_line
763        );
764        message_print(
765            log_rec_ptr->msgs.msg_id,
766	    log_rec_ptr->msgs.arg[0],
767	    log_rec_ptr->msgs.arg[1],
768	    log_rec_ptr->msgs.arg[2],
769	    log_rec_ptr->msgs.arg[3],
770	    log_rec_ptr->msgs.arg[4]
771        );
772    }
773
774    for (erp = log_rec_ptr->first_this_line; erp; erp=erp->links.asList.next)
775    {
776        /* Print the error only if it in this file */
777        if (source_id == erp->filename)
778        {
779            /* If we haven't output the source line text yet, the do so */
780            if (!source_printed)
781            {
782                source_printed = true;
783                seek_for_line(fd, log_rec_ptr->lineno, source_line);
784                message_print(
785                    NIDL_FILESOURCE, source, log_rec_ptr->lineno, source_line
786                );
787            }
788
789            /* Now print out the actual error message */
790	    message_print(
791			  erp->msgs.msg_id,
792			  erp->msgs.arg[0],
793			  erp->msgs.arg[1],
794			  erp->msgs.arg[2],
795			  erp->msgs.arg[3],
796			  erp->msgs.arg[4]
797			 );
798        }
799    }
800}
801
802/*
803 *  p r i n t _ e r r o r _ m e s s a g e s
804 *
805 *  Function:   Recursively prints all accumulated error messages.
806 *
807 *  Inputs:     fd          - file descriptor for source file
808 *              source      - name of source file
809 *              log_rec_ptr - root of error log tree
810 */
811
812void print_error_messages
813(
814    FILE *fd,
815    char const *source,
816    STRTAB_str_t    source_id,
817    error_log_rec_t *log_rec_ptr
818)
819{
820    if (log_rec_ptr->links.asBinTree.left != NULL)
821        print_error_messages(fd, source, source_id, log_rec_ptr->links.asBinTree.left);
822
823    print_errors_for_line(fd, source, source_id, log_rec_ptr);
824
825    if (log_rec_ptr->links.asBinTree.right != NULL)
826        print_error_messages(fd, source, source_id, log_rec_ptr->links.asBinTree.right);
827}
828
829/*
830 *  p r i n t _ e r r o r s
831 *
832 *  Function:   Prints all accumulated error messages.
833 *
834 *  Inputs:     source - String table ID of source file name
835 *
836 *  Functional value:   true - if any errors were printed
837 *                      false otherwise
838 *
839 */
840
841boolean print_errors
842(
843    void
844)
845
846{
847    FILE       *fd;
848    char const *fn;
849    int        i;
850    STRTAB_str_t   source_id;
851    error_log_rec_t *error_root;
852
853    /*
854     * If there are no errors, just return
855     */
856     if (errors == NULL) return 0;
857
858    /*
859     * Copy the root of the error tree and null it out so that
860     * it looks like all the errors have been printed if we get
861     * an error while printing them out.
862     */
863     error_root = errors;
864     errors = NULL;
865
866    /*
867     * Loop through all files with errors
868     */
869    for (i = 0; i < error_file_count; i++)
870    {
871        source_id = error_files[i];
872        STRTAB_str_to_string(source_id, &fn);
873        fd = fopen(fn, "r");
874        print_error_messages(fd, fn, source_id, error_root);
875        last_error_line = 0;
876    }
877
878    /*
879     * Free the tree of errors,
880     */
881    free_log_rec(error_root);
882    error_file_count = 0;
883
884    /*
885     * Return true if we found any errors.
886     */
887    return (error_file_count != 0);
888}
889
890/*
891 *  e r r o r
892 *
893 *  Function:   Prints the specifed error message and terminates the program
894 *
895 *  Inputs:     msg_id - the error message ID.
896 *              [arg1,...,arg5] - 0 to 5 arguments for error message formatting
897 *
898 *  Notes:      This call terminates the calling program with a failure status
899 *
900 */
901
902void error
903(
904    long msg_id,
905    ...
906)
907{
908	va_list arglist;
909
910    if (current_file)
911        message_print(NIDL_LINEFILE, current_file,
912				yylineno_p ? *yylineno_p : 0);
913
914	va_start (arglist, msg_id);
915	vmessage_print (msg_id, arglist);
916	va_end (arglist);
917
918#ifndef HASPOPEN
919    sysdep_cleanup_temp();
920#endif
921
922    nidl_terminate();
923}
924
925/*
926 *  e r r o r _ l i s t
927 *
928 *  Function:   Prints the specifed error message(s) and terminates the program
929 *
930 *  Inputs:     vecsize - number of messages
931 *              errvec - pointer to one or more message info elements
932 *              exitflag - TRUE => exit program
933 *
934 *  Notes:      This call terminates the calling program with a failure status
935 *
936 */
937
938void error_list
939(
940    int vecsize,
941    idl_error_list_p errvec,
942    boolean exitflag
943)
944{
945    int i;
946
947    for (i = 0; i < vecsize; i++)
948	{
949		message_print(errvec[i].msg_id,
950				  errvec[i].arg[0],
951				  errvec[i].arg[1],
952				  errvec[i].arg[2],
953				  errvec[i].arg[3],
954				  errvec[i].arg[4]
955				 );
956	}
957
958    if (!exitflag) return;
959
960#ifndef HASPOPEN
961    sysdep_cleanup_temp();
962#endif
963
964    nidl_terminate();
965}
966
967/*
968 *  w a r n i n g
969 *
970 *  Function:   Prints the specifed error message. Terminates if the
971 *              error count excees the threshold.
972 *
973 *  Inputs:     msg_id - the error message ID.
974 *              [arg1,...,arg5] - 0 to 5 arguments for error message formatting
975 *
976 *  Globals:    yylineno_p
977 *
978 *  Notes:      This call terminates the calling program with a status of -2.
979 *
980 */
981
982void warning
983(
984 long msg_id,
985 ...
986)
987{
988	va_list arglist;
989
990    /* Return if warnings are suppressed. */
991    if (ERR_no_warnings)
992        return;
993
994    if (current_file)
995        message_print(NIDL_LINEFILE, current_file,
996				yylineno_p ? *yylineno_p : 0);
997
998	va_start (arglist, msg_id);
999	vmessage_print (msg_id, arglist);
1000	va_end (arglist);
1001
1002    if (++warnings > MAX_WARNINGS)
1003    {
1004        message_print(NIDL_MAXWARN, MAX_WARNINGS);
1005        nidl_terminate();
1006    }
1007}
1008
1009/*
1010 *  s e t _ n a m e _ f o r _ e r r o r s
1011 *
1012 *  Function:   Records the name of the file being processed.  This name
1013 *              will be prepended onto error messages.
1014 *
1015 *  Inputs:     name - a pointer to the file name.
1016 *
1017 */
1018
1019void set_name_for_errors
1020(
1021    char const *filename
1022)
1023{
1024    if (filename != NULL)
1025    {
1026        error_file_name_id = STRTAB_add_string(filename);
1027        STRTAB_str_to_string(error_file_name_id, &current_file);
1028    }
1029    else
1030	{
1031		current_file = NULL;
1032	}
1033}
1034
1035/*
1036 *  i n q _ n a m e _ f o r _ e r r o r s
1037 *
1038 *  Function:   Returns the name of the file being processed.
1039 *
1040 *  Outputs:   name - the file name is copied through this.
1041 *
1042 */
1043
1044void inq_name_for_errors
1045(
1046    char *name,
1047	size_t name_len
1048)
1049{
1050    if (current_file)
1051        strlcpy(name, current_file, name_len);
1052    else
1053        *name = '\0';
1054}
1055
1056/* preserve coding style vim: set tw=78 sw=4 ts=4: */
1057