1 /*
2  *      $Id: ErrLog.c 191 2007-03-30 23:26:38Z boote $
3  */
4 /************************************************************************
5 *									*
6 *			     Copyright (C)  2002			*
7 *				Internet2				*
8 *			     All Rights Reserved			*
9 *									*
10 ************************************************************************/
11 /*
12  *	File:		ErrLog.c
13  *
14  *	Author:		Jeff Boote
15  *			Internet2
16  *
17  *	Date:		Tue Apr 23 09:11:05  2002
18  *
19  *	Description:
20  *		Generic error logging routines.
21  *
22  *
23  *		Based on code from UCAR DCS tools. Copyright information
24  *		from UCAR follows:
25  *
26  *		Copyright 1997 University Corporation for Atmospheric Research,
27  *		Scientific Computing Division.  All rights reserved.
28  *
29  *
30  *		Permission to use, copy, modify and distribute this software
31  *		and its	documentation for any academic, educational and
32  *		scientific research purpose is hereby granted without fee,
33  *		provided that the above copyright notice and this permission
34  *		notice appear in all copies of this software and its
35  *		documentation, and that the software is not sold and/or made
36  *		the subject of any commercial activity.  Parties interested
37  *		in commercial licensing should contact the copyright holder.
38  *
39  */
40 #include <I2util/utilP.h>
41 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <stdarg.h>
45 #include <string.h>
46 #include <errno.h>
47 #include "mach_dep.h"
48 
49 
50 /*
51  * May support threading in future.
52  */
53 static I2ThreadMutex_T	MyMutex = I2PTHREAD_MUTEX_INITIALIZER;
54 
55 #define	TABLE_SIZE	10
56 #define	MSG_BUF_SIZE	10240
57 
58 /*
59  *	 an error table. Error table[0] contains sys_errlist.
60  */
61 typedef	struct	ErrTable_ {
62 	unsigned	start,		/* starting index for err_list	*/
63 			num;		/* num elements in err_list	*/
64 	const char	**err_list;	/* error messags		*/
65 	} ErrTable;
66 
67 
68 /*
69  * static variables that contain the file name and line number of the most
70  * recently logged error via a call to I2ErrLocation_().
71  *
72  * N.B. I2ErrLocation_() should never be called directly by a client
73  * of the error module. I2ErrLocation_() is invoked via the macro call
74  * I2ErrLog() which calls I2ErrLocation_() and then immediately calls
75  * I2ErrLogFunction_(). This enables multiple instances of an error
76  * logging session w/out having to maintain the current file and line
77  * number as a separate state variable for each session with some degree
78  * of security. In a threaded environment access to these variables is
79  * locked by I2ErrLocation_() and unlocked by I2ErrLogFunction_(). All of
80  * this is necessary because the only way to automatically generate the
81  * line number and file name information automatically is via and macro
82  * call (as opposed to a function call) and macros don't accept variable
83  * number of arguments
84  */
85 static const char	*errorFile = "";
86 static const char	*errorDate = "";
87 static int		errorLine = 0;
88 
89 
90 /*
91  * An error handle struct. This struct maintains the state of an
92  * error reporting session created via I2ErrOpen()
93  */
94 typedef	struct	ErrHandle_ {
95 	ErrTable	err_tab[TABLE_SIZE];	/* all the error tables	*/
96 	int		err_tab_num;		/* num error tables	*/
97 	int		code;		/* error code of last error */
98 	const char	*program_name;		/* name of calling prog	*/
99 	void		*data;			/* client data		*/
100 	I2ErrLogFuncPtr	log_func;		/* client loggin func	*/
101 	void		*log_func_arg;		/* client arg to log func*/
102 	I2ErrRetrieveFuncPtr	retrieve_func;	/* client fetch func	*/
103 	void		*retrieve_func_arg;	/* client arg to retrieve func*/
104 	I2ErrLogResetFuncPtr	reset_func;	/* reset log_func	*/
105 	} ErrHandle;
106 
107 /*
108  * fetch an error message associated with a given error code. Return
109  * an empty string if no matching error message is found.
110  */
get_error(ErrHandle * eh,int error)111 static	const char	*get_error(ErrHandle *eh, int error)
112 {
113 	int		i;
114 	unsigned int	index;
115 	unsigned int	errnum;
116 
117 	if(error < 0)
118 		return("");
119 	errnum = (unsigned int)error;
120 
121 	if(!eh){
122 		return strerror(errnum);
123 	}
124 
125 	for (i=0; i<eh->err_tab_num; i++) {
126 		if(eh->err_tab[i].start > errnum)
127 			continue;
128 		index = errnum - eh->err_tab[i].start;
129 		if ((unsigned)errnum >= eh->err_tab[i].start &&
130 					index < eh->err_tab[i].num) {
131 
132 			return(eh->err_tab[i].err_list[index]);
133 		}
134 	}
135 
136 	return("");
137 }
138 
139 /*
140  * format an error message converting any `%M' tokens to the error
141  * string associated with error message number `code, and any
142  * `%N' tokens to the ascii representation of the value of `code
143  *
144  * `buf' must have enough space to hold the new string
145  */
esnprintf(ErrHandle * eh,char * buf,size_t size_buf,const char * format,int code)146 static int	esnprintf(
147 	ErrHandle	*eh,
148 	char		*buf,
149 	size_t		size_buf,
150 	const char	*format,
151 	int		code
152 ) {
153 	const char	*p1;
154 	char		*p2;
155 	size_t		size_p2 = size_buf;
156 	int		len;
157 
158 
159 	for(p1=format, p2=buf; *p1 && (size_p2 > 1); p1++, p2++, size_p2--) {
160 		if (*p1 != '%') {
161 			*p2 = *p1;
162 			continue;
163 		}
164 		p1++;
165 		if (*p1 == 'M') {
166 			len =snprintf(p2,size_p2,"%s",get_error(eh,code))-1;
167 			p2 += len;
168 			size_p2 -= len;
169 		}
170 		else if (*p1 == 'N') {
171 			len = snprintf(p2,size_p2,"%d", code) - 1;
172 			p2 += len;
173 			size_p2 -= len;
174 		}
175 		else {
176 			*p2++ = '%';
177 			size_p2--;
178 			*p2 = *p1;
179 		}
180 	}
181 	*p2 = '\0';
182 
183 	return(strlen(buf));
184 }
185 
add_ansiC_errors(ErrHandle * eh)186 void	add_ansiC_errors(ErrHandle *eh)
187 {
188 	char	**sys_errlist;		/* list of errors	*/
189 	int	errlist_size;		/* size of $sys_errlist	*/
190 
191 	/*
192 	**	Get the list of system errors supported on this platform
193 	*/
194 	sys_errlist = I2GetSysErrList(&errlist_size);
195 
196 	eh->err_tab_num = 0;
197 	(void) I2ErrList(
198 		(I2ErrHandle) eh, 0, errlist_size, (const char **) sys_errlist);
199 }
200 
201 /*
202 **
203 **	A P I
204 **
205 */
206 
207 /*
208  * Function:	I2ErrOpen()
209  *
210  * Description:	The I2ErrOpen() function starts an error reporting session
211  *		and returns an error handle associated with that session.
212  *
213  *		The `log_func' argument is a pointer to a logging function
214  *		that is to be called whenever an error is logged with the
215  *		I2ErrLog() macro. This function may be user-defined or may
216  *		be one of the pre-defined functions (I2LogFuncStack_()
217  *		or I2LogFuncImmediate_()).
218  *
219  *		The `retrieve_func' argument is a pointer to a error
220  *		log retrieval function that is invoked to fetch error
221  *		messages logged with the function pointed to by
222  *		`log_func'. `retrive_func' may be NULL if no such
223  *		function exists.
224  *
225  * In Args:
226  *
227  *	*program_name	A pointer to a character string specifying the
228  *			name of the calling program (or any other piece
229  *			of information you might wish).
230  *
231  *	*log_func	A pointer to a user-defined error logging function
232  *			as described below.
233  *
234  *	*log_func_arg	A pointer to user-defined data that is to be passed
235  *			to the logging function whenever the logging
236  *			function is invoked.
237  *
238  *	*retrieve_func	A pointer to a user-defined error retrieval function
239  *			as described below.
240  *
241  *	*ret_func_arg	A pointer to user-defined data that is to be passed
242  *			to the retrieval function whenever the retrieval
243  *			function is invoked.
244  *
245  *
246  * Out Args:
247  *
248  * Return Values:	An error handle is returned upon success. Otherwise
249  *			NULL is returned and the global variable `errno'
250  *			is set accordingly
251  *
252  * Side Effects:
253  *
254  *
255  * The Logging Function
256  *
257  *	The logging function pointed to by `log_func' is called indirectly
258  *	by the I2ErrLog() macro to log error messages. The `program_name'
259  *	parameter points to the array pointed to by the parameter of the
260  *	same name passed to I2ErrOpen(). The logging function is also provided
261  *	provided with the name of the file from whence I2ErrOpen() was
262  *	called, `file', as well as the line number, `line', the date the
263  *	file was compiled, `date', the error message to be logged, `msg',
264  *	the user-defined logging function argument passed to I2ErrOpen(),
265  *	`arg', and a hook for any state context the logging function
266  *	needs to maintain, `data'.
267  *
268  * In Args:
269  *
270  *	*program_name	A pointer to the character string passed to
271  *			I2ErrOpen() as its first argument.
272  *
273  *	*file		A pointer to a string containing the name of the
274  *			file from whence I2ErrLog() was called.
275  *
276  *	line		An integer indicating the line number within
277  *			`file' from whence I2ErrLog() was called.
278  *
279  *	*date		A pointer to a string containing the date (of the
280  *			file from which I2ErrLog() was called) was compiled.
281  *
282  *	*msg		A pointer to string containing the error message
283  *			to be logged.
284  *
285  *	*arg		A pointer to the `log_func_arg' argument passed to
286  *			I2ErrOpen()
287  *
288  *	**data		A pointer to a pointer to be used by the logging
289  *			function in any desired manner. `*data' is NULL
290  *			unless changed by the logging function
291  *
292  * The Retrieval Function
293  *
294  *	The retrieval function pointed to by `retrieve_func' is invoked
295  *	whenever the error messages  logged by the logging function are
296  *	to be retrieved. The retrieval function is passed the same hook,
297  *	`data', for maintaining state information as the logging function,
298  *	and the user-defined argument, `arg', passed to the I2ErrOpen()
299  *	function as `retreive_func_arg'.
300  *
301  *	The retrieval function should return a pointer to an area of
302  *	dynamically allocated memory containing a character string
303  *	representing the error messages logged with previous calls
304  *	to the logging function. The caller will free the memory
305  *	returned by the retrieval function.
306  *
307  * In Args
308  *
309  *	*arg		A pointer to the `retrieve_func_arg' argument passed to
310  *			I2ErrOpen()
311  *
312  *	**data		A pointer to a pointer to be used by the retrieval
313  *			function in any desired manner. `*data' is NULL
314  *			unless changed by the logging function
315  *
316  */
I2ErrOpen(const char * program_name,I2ErrLogFuncPtr log_func,void * log_func_arg,I2ErrRetrieveFuncPtr retrieve_func,void * retrieve_func_arg)317 I2ErrHandle	I2ErrOpen(
318 		const char		*program_name,
319 		I2ErrLogFuncPtr		log_func,
320 		void			*log_func_arg,
321 		I2ErrRetrieveFuncPtr	retrieve_func,
322 		void			*retrieve_func_arg
323 ) {
324 
325 	ErrHandle	*eh;
326 
327 	if (! log_func) {
328 		errno = EINVAL;
329 		return(NULL);
330 	}
331 
332 	if (! (eh = malloc(sizeof(ErrHandle)))) {
333 		return(NULL);
334 	}
335 
336 	eh->code = 0;
337 	eh->program_name = program_name;
338 	eh->log_func = log_func;
339 	eh->log_func_arg = log_func_arg;
340 	eh->retrieve_func = retrieve_func;
341 	eh->retrieve_func_arg = retrieve_func_arg;
342 	eh->data = NULL;
343 
344 
345 	/*
346 	 * add the Standard C Library error messages
347 	 */
348 	add_ansiC_errors(eh);
349 
350 	return((I2ErrHandle) eh);
351 }
352 
353 /*
354  * Function:	I2ErrSetResetFunc
355  *
356  * Description:
357  * 		Used to assign the "reset" function. Not used, so it
358  * 		was not useful to add to the "open". (Plus, it would
359  * 		be hard to make "open" backward compat.)
360  *
361  * In Args:
362  *
363  * Out Args:
364  *
365  * Scope:
366  * Returns:
367  * Side Effect:
368  */
I2ErrSetResetFunc(I2ErrHandle dpeh,I2ErrLogResetFuncPtr reset_func)369 void	I2ErrSetResetFunc(
370 		I2ErrHandle		dpeh,
371 		I2ErrLogResetFuncPtr	reset_func
372 	)
373 {
374 	ErrHandle	*eh = (ErrHandle *) dpeh;
375 
376 	eh->reset_func = reset_func;
377 
378 	return;
379 }
380 
381 /*
382  * Function:	I2ErrReset
383  *
384  * Description:
385  * 		If there is a "reset_func" assigned to the ErrHandle,
386  * 		call it.
387  *
388  * In Args:
389  *
390  * Out Args:
391  *
392  * Scope:
393  * Returns:
394  * Side Effect:
395  */
396 I2ErrHandle
I2ErrReset(I2ErrHandle dpeh)397 I2ErrReset(
398 		I2ErrHandle	dpeh
399 		)
400 {
401 	ErrHandle	*eh = (ErrHandle *) dpeh;
402 
403 	if(eh->reset_func){
404 		if(!(eh->reset_func(eh->log_func_arg, &(eh->data)))){
405 			I2ErrClose(dpeh);
406 			return NULL;
407 		}
408 	}
409 
410 	return dpeh;
411 }
412 
413 /*
414  * Function:	I2ErrClose()
415  *
416  * Description:	This function closes the error handling session associated
417  *		with `dpeh'.
418  *
419  * In Args:
420  *
421  *	dpeh		An error handle returned via a call to I2ErrOpen().
422  *
423  * Out Args:
424  *
425  * Return Values:
426  *
427  * Side Effects:
428  */
I2ErrClose(I2ErrHandle dpeh)429 void	I2ErrClose(I2ErrHandle dpeh)
430 {
431 	ErrHandle *eh = (ErrHandle *) dpeh;
432 
433 	if (eh) free(eh);
434 }
435 
436 /*
437  * Function:	I2ErrRep()
438  *
439  * Description: The I2ErrRep() function calls the client retrieval function
440  *		(if one exists) passed to I2ErrOpen() for the error
441  *		handling session associated with `dpeh'. I2ErrRep() copies
442  *		the program name, followed by a ":", followed by a space,
443  *		followed by the character string returned by the client
444  *		retrieval function, followed by a newline, to the file
445  *		pointer, `fp'. The character string returned by the
446  *		retrieval function is then freed with a call to free().
447  *
448  * In Args:
449  *
450  *	dpeh		An error handle returned via a call to I2ErrOpen().
451  *
452  *	fp		A pointer to a file stream.
453  *
454  * Out Args:
455  *
456  * Return Values:
457  *
458  * Side Effects:
459  */
I2ErrRep(I2ErrHandle dpeh,FILE * fp)460 void	I2ErrRep(
461 	I2ErrHandle	dpeh,
462 	FILE		*fp
463 ) {
464 	ErrHandle *eh = (ErrHandle *) dpeh;
465 	char		*msg;
466 
467 
468 	if (! eh) return;
469 
470 	I2ThreadMutexLock(&MyMutex);
471 
472 	if (eh->retrieve_func) {
473 		msg = eh->retrieve_func(eh->retrieve_func_arg, &(eh->data));
474 		(void) fprintf(fp, "%s:\n", eh->program_name);
475 		(void) fprintf(fp, "%s\n", msg);
476 		free(msg);
477 	}
478 	I2ThreadMutexUnlock(&MyMutex);
479 
480 }
481 
482 /*
483  * Function:	I2ErrGetMsg()
484  *
485  * Description: The I2ErrGetMsg() function calls the client retrieval function
486  *		(if one exists) passed to I2ErrOpen() for the error
487  *		handling session associated with `dpeh'. I2ErrGetMsg() returns
488  *		to the caller the value returned to it by the client
489  *		retrieval function (an address in dynamically allocated memory
490  *		of a character string). The caller is responsible for freeing
491  *		the memory returned by I2ErrGetMsg().
492  *
493  * In Args:
494  *
495  *	dpeh		An error handle returned via a call to I2ErrOpen().
496  *
497  * Out Args:
498  *
499  * Return Values:	I2ErrGetMsg() returns NULL if no retrieval function
500  * 			exists.
501  *
502  * Side Effects:
503  */
I2ErrGetMsg(I2ErrHandle dpeh)504 char	*I2ErrGetMsg(
505 	I2ErrHandle	dpeh
506 ) {
507 	ErrHandle	*eh = (ErrHandle *) dpeh;
508 	char		*msg;
509 
510 	I2ThreadMutexLock(&MyMutex);
511 
512 	if (eh && eh->retrieve_func) {
513 		msg = eh->retrieve_func(eh->retrieve_func_arg, &(eh->data));
514 	}
515 	else {
516 		msg = NULL;
517 	}
518 
519 	I2ThreadMutexUnlock(&MyMutex);
520 
521 	return(msg);
522 }
523 
524 
525 
526 /*
527  * Function:	I2ErrGetCode()
528  *
529  * Description: The I2ErrGetCode() function returns the error number currently
530  *		associated with the error handle, `dpeh'.
531  *
532  *		N.B. the error code returned is the error code stored from
533  *		the most *recent* call to I2ErrLog() or I2ErrLogP(). If
534  *		you are nesting calls to these functions only the error
535  *		code from the outer-most logging function is available - i.e
536  *		inner calls get overwritten.
537  *
538  * In Args:
539  *
540  *	dpeh		An error handle returned via a call to I2ErrOpen().
541  *
542  * Out Args:
543  *
544  * Return Values:	I2ErrGetCode() returns an integer.
545  *
546  * Side Effects:
547  */
I2ErrGetCode(I2ErrHandle dpeh)548 int	I2ErrGetCode(
549 	I2ErrHandle	dpeh
550 ) {
551 	ErrHandle	*eh = (ErrHandle *) dpeh;
552 
553 	return(eh->code);
554 }
555 
556 
557 
558 
559 /*
560  *	I2ErrList()
561  *
562  *	Adds an error list to the error table. 'start' should be the first
563  *	valid error number for this table. The values 0 - 1000 are reserved.
564  *	The index into 'err_list' is calculated by subtracting 'start'
565  *	from the error number. Thus if you add a list with 'start' equal
566  *	to 1001 and later invoke ESprintf with 'code' equal to 1001 the
567  *	error message referenced will be 'err_list[0]'
568  *
569  * on entry
570  *	start		: first valid error number
571  *	num		: number of elements in 'err_list'.
572  *	**err_list	: address of error list
573  *
574  * on exit
575  *	return		: -1 => table full, else OK.
576  */
I2ErrList(I2ErrHandle dpeh,unsigned start,unsigned num,const char ** err_list)577 int	I2ErrList(
578 	I2ErrHandle 	dpeh,
579 	unsigned 	start,
580 	unsigned 	num,
581 	const char 	**err_list
582 ) {
583 
584 	ErrHandle *eh = (ErrHandle *) dpeh;
585 
586 	if (! eh) return(0);
587 
588 	if (eh->err_tab_num >= TABLE_SIZE -1) {
589 		return(-1);	/* table full	*/
590 	}
591 
592 	eh->err_tab[eh->err_tab_num].start = start;
593 	eh->err_tab[eh->err_tab_num].num = num;
594 	eh->err_tab[eh->err_tab_num].err_list = err_list;
595 	eh->err_tab_num++;
596 
597 	return(0);
598 }
599 
600 
601 
602 /*
603  * Function:	I2ErrLocation_
604  *
605  * Description: The I2ErrLocation_() records the file name, `file', line
606  *		number, `line', and compilation date, `date' reported by
607  *		the I2ErrLog() macro. This function should never be
608  *		called directly by the user himself.
609  *
610  * In Args:
611  *
612  *	*file		A pointer to a character string containing a file
613  *			name.
614  *
615  *	*date		A pointer to a character string containing the
616  *			compiliation date of `file'
617  *
618  *	line		An integer specifying a line number within the
619  *			file, `file'.
620  *
621  * Out Args:
622  *
623  * Return Values:
624  *
625  * Side Effects:
626  *
627  *		I2ErrLocation_() writes the global, static variables,
628  *		`errorFile', `errorDate', and `errorLine'. In order to
629  *		be thread-save this function should lock these variables
630  *		before attemping to write them (it does if `THREADS_ENABLE'
631  *		is defined). The variables should then
632  *		remain locked until unlocked by I2ErrLogFunction() or
633  *		I2ErrLogPFunction().
634  */
I2ErrLocation_(const char * file,const char * date,int line)635 void	I2ErrLocation_(
636 	const char	*file,
637 	const char	*date,
638 	int		line
639 ) {
640 
641 	I2ThreadMutexLock(&MyMutex);
642 
643 	errorFile = file;
644 	errorDate = date;
645 	errorLine = line;
646 }
647 
648 /*
649  * Function:	I2ErrLogPFunction_()
650  *
651  * Description:	The I2ErrLogPFunction() is identical to the I2ErrLogFunction()
652  *		except that it is invoked by the I2LogPErr() macro which
653  *		takes an additional error code argument that is passed
654  *		on to I2ErrLogPFunction_(), `code'
655  *
656  *		`code' may be any valid value of the system global
657  *		variable, `errno', or it may be an error code made valid
658  *		by a call to I2ErrList().
659  *
660  *
661  *
662  * In Args:
663  *
664  *	dpeh		An error handle returned via a call to I2ErrOpen().
665  *
666  *	code	An integer indicating the error number.
667  *
668  *	*format		A pointer to a character string containing formating
669  *			information.
670  *
671  *	...		variable arguments as indicated in `format'
672  *
673  * Out Args:
674  *
675  * Return Values:
676  *
677  * Side Effects:
678  */
679 void
I2ErrLogVT(I2ErrHandle dpeh,int level,int code,const char * format,va_list ap)680 I2ErrLogVT(
681 	I2ErrHandle	dpeh,
682 	int		level,
683 	int		code,
684 	const char	*format,
685 	va_list		ap
686 )
687 {
688 	ErrHandle		*eh = (ErrHandle *) dpeh;
689 	char			new_format[MSG_BUF_SIZE];
690 	char			buf[MSG_BUF_SIZE];
691 	struct I2ErrLogEvent	event;
692 
693         if(level == I2LOG_NONE)
694             return;
695 
696 	event.mask = 0;
697 
698 	if(!code)
699 		code = errno;
700 	else{
701 		event.code = code;	event.mask |= I2CODE;
702 	}
703 
704 	(void)esnprintf(eh,new_format,sizeof(new_format),format,code);
705 
706 	/*
707 	 * deal with variable args
708 	 */
709         (void) vsnprintf(buf,sizeof(buf),new_format,ap);
710 
711 	if(!eh){
712 		fwrite(buf,sizeof(char),strlen(buf),stderr);
713 		fwrite("\n",sizeof(char),1,stderr);
714 		I2ThreadMutexUnlock(&MyMutex);
715 		return;
716 	}
717 
718 	eh->code = code;
719 	event.name = eh->program_name;	event.mask |= I2NAME;
720 	event.file = errorFile;		event.mask |= I2FILE;
721 	event.line = errorLine;		event.mask |= I2LINE;
722 	event.date = errorDate;		event.mask |= I2DATE;
723 	event.msg = buf;		event.mask |= I2MSG;
724 
725 	if(level > -1 && level < 8){
726 		event.level = level;	event.mask |= I2LEVEL;
727 	}
728 
729 	eh->log_func(
730 		&event, eh->log_func_arg, &(eh->data)
731 	);
732 	I2ThreadMutexUnlock(&MyMutex);
733 
734 	return;
735 }
736 
737 void
I2ErrLogTFunction_(I2ErrHandle dpeh,int level,int code,const char * format,...)738 I2ErrLogTFunction_(
739 	I2ErrHandle	dpeh,
740 	int		level,
741 	int		code,
742 	const char	*format,
743 	...
744 )
745 {
746 	va_list		ap;
747 
748         va_start(ap, format);
749 	I2ErrLogVT(dpeh,level,code,format,ap);
750         va_end(ap);
751 
752 	return;
753 }
754 
755 /*
756  * Function:	I2ErrLogPFunction_()
757  *
758  * Description:	The I2ErrLogPFunction() is identical to the I2ErrLogFunction()
759  *		except that it is invoked by the I2LogPErr() macro which
760  *		takes an additional error code argument that is passed
761  *		on to I2ErrLogPFunction_(), `code'
762  *
763  *		`code' may be any valid value of the system global
764  *		variable, `errno', or it may be an error code made valid
765  *		by a call to I2ErrList().
766  *
767  *
768  *
769  * In Args:
770  *
771  *	dpeh		An error handle returned via a call to I2ErrOpen().
772  *
773  *	code	An integer indicating the error number.
774  *
775  *	*format		A pointer to a character string containing formating
776  *			information.
777  *
778  *	...		variable arguments as indicated in `format'
779  *
780  * Out Args:
781  *
782  * Return Values:
783  *
784  * Side Effects:
785  */
I2ErrLogPFunction_(I2ErrHandle dpeh,int code,const char * format,...)786 void	I2ErrLogPFunction_(
787 	I2ErrHandle	dpeh,
788 	int		code,
789 	const char	*format, ...
790 )
791 {
792 	va_list		ap;
793 
794         va_start(ap, format);
795 	I2ErrLogVT(dpeh,-1,code,format,ap);
796         va_end(ap);
797 
798 	return;
799 }
800 
801 /*
802  * Function:	I2ErrLogFunction_()
803  *
804  * Description:	The I2ErrLogFunction() converts and formats its arguments
805  *		under the control of `format'. I2ErrLogFunction_()
806  *		then invokes the client-supplied logging function associated
807  *		with `dpeh' and passes it the formatted argument string.
808  *
809  *		`format' is a character string which accepts an identical
810  *		syntax to that of Standard C's *printf family of functions.
811  *		Additionaly, `format' may contain instances of the format
812  *		specifier, "%M", which are replaced by the UNIX system
813  *		error message associated with `errno', and instances of
814  *		the specifier "%N", which are replaced with the ascii value
815  *		of `errno'.
816  *
817  *		I2ErrLogFunction() is never invoked directly by the user.
818  *		Instead, it is invoked via the I2ErrLog() macro, which
819  *		calls I2ErrLocation_() first, passing it the error location
820  *		information.
821  *
822  *
823  *
824  * In Args:
825  *
826  *	dpeh		An error handle returned via a call to I2ErrOpen().
827  *
828  *	*format		A pointer to a character string containing formating
829  *			information.
830  *
831  *	...		variable arguments as indicated in `format'
832  *
833  * Out Args:
834  *
835  * Return Values:
836  *
837  * Side Effects:
838  */
I2ErrLogFunction_(I2ErrHandle dpeh,const char * format,...)839 void	I2ErrLogFunction_(
840 	I2ErrHandle	dpeh,
841 	const char	*format, ...
842 )
843 {
844 	va_list		ap;
845 
846         va_start(ap, format);
847 	I2ErrLogVT(dpeh,-1,0,format,ap);
848         va_end(ap);
849 
850 	return;
851 }
852