CARMA C++
lprintf.h
1 #ifndef lprintf_h
2 #define lprintf_h
3 
4 #include "carma/szautil/Logger.h"
5 
6 #include <stdio.h>
7 #include <stdarg.h>
8 
9 /*
10  * lprintf() is a drop-in replacement to fprintf() and printf()
11  * designed for redirecting stdout and/or stderr messages to alternate
12  * logging channels such as message queues, TCP/IP streams, widgets
13  * etc.. Note that lprintf(stream,...) will behave identically to
14  * fprintf(stream,...) until divert_lprintf(stream,...) is called to
15  * register a logging function to that stream.
16  *
17  * A limitation of this facility is that when logging to a function is
18  * enabled, individual messages are truncated at LOG_MSGLEN bytes
19  * (actually LOG_MSGLEN+1 when account is take of the trailing '\0').
20  *
21  * Note that the combination of lprintf() and print_format() [and
22  * presumably its vxWorks equivalent, fioFormatV()] use about 750
23  * bytes of stack space.
24  *
25  * Threads issues:
26  * In pthreads programs be sure to define the _POSIX_C_SOURCE macro
27  * to be at least 199506L during compilation of all files that include
28  * lprintf.h (including lprintf.c).
29  *
30  * In VxWorks programs define VXW when compiling any file that includes
31  * lprintf.h, and call vw_install_lprintf() before creating the first task
32  * [apart from the caller of vw_install_lprintf()] that will use lprintf().
33  * If subsequently you need to deinstall the module that contains lprintf(),
34  * make sure that all tasks that use lprintf() have been deleted (with the
35  * possible exception of the task that calls vw_remove_lprintf()), then
36  * call vw_remove_lprintf() to remove the task creation and deletion
37  * hooks that were installed by vw_install_lprintf().
38  *
39  * Provided that the above guidlines are followed, divert_lprintf()
40  * and lprintf() will operate on a per thread basis. In particular,
41  * when logging functions are registered to a thread, the associated
42  * streams will be line buffered on a per thread basis to prevent
43  * interleaving of partial lines from different threads.
44  */
45 
46 /*
47  * VxWorks installation and removal functions for lprintf().
48  * See the above discussion of "Threads issues".
49  */
50 #ifdef VXW
51 int vw_install_lprintf(void);
52 int vw_remove_lprintf(void);
53 #endif
54 
55 /*
56  * The following is the length of the longest log message
57  * (excluding '\0'). Longer messages will be truncated before
58  * being dispatched to the function registered to the associated
59  * stream.
60  */
61 #define LOG_MSGLEN 127
62 
63 /*
64  * When this header is compiled with gcc, the following macro
65  * is expanded at the end of the prototype of lprintf. The
66  * result informs gcc that the format and trailing arguments should
67  * be checked as though the function were printf().
68  */
69 #undef CHECK_FORMAT
70 #ifdef __GNUC__
71 #define CHECK_FORMAT __attribute__ ((format (printf, 2, 3)))
72 #else
73 #define CHECK_FORMAT
74 #endif
75 
76 /*
77  * The following functions are drop-in logging replacements for the
78  * similarly named stdio functions. When logging is disabled, they
79  * behave identically to their stdio counterparts.
80  */
81 int lprintf(FILE *stream, const char *fmt, ...) CHECK_FORMAT;
82 #undef CHECK_FORMAT
83 
84 int vlprintf(FILE *stream, const char *fmt, va_list ap);
85 int lputc(int c, FILE *stream);
86 int lputs(const char *s, FILE *stream);
87 int lflush(FILE *stream);
88 
89 namespace sza {
90  namespace array {
91  /*
92  * The dispatch function is passed an enumerated equivalent of
93  * stdout or stderr, depending upon which stream the caller
94  * presented to lprintf(). This is useful if a single
95  * dispatch function is registered to both stdout and stderr.
96  */
97  enum LogStream {
98  LOG_STDOUT, /* Log to stdout */
99  LOG_STDERR /* Log to stderr */
100  };
101 
102  };
103 };
104 
105 /*
106  * Application-specific dispatch functions and their prototypes
107  * should be declared using the following macro. The arguments
108  * of a dispatch function are used as follows:
109  *
110  * Input:
111  * message char * The latest message composed by lprintf().
112  * This will be at most LOG_MSGLEN+1 bytes in
113  * length and will '\0' terminated, regardless
114  * of whether the message had to be truncated.
115  * Note that the trailing newline is omitted.
116  * id LogStream The identity of the stream that the caller
117  * of lprintf() cited. This is only useful if
118  * the same dispatch function has been assigned
119  * to stdout and stderr.
120  * context void * The value of the 'context' argument of
121  * divert_lprintf() when the dispatch function
122  * was registered. Note that in a threaded
123  * environment, modifications to this context
124  * will need to be semaphore protected.
125  * Output:
126  * return int 0 - The message was logged without error.
127  * 1 - An error occured. This tells lprintf()
128  * to return -1 instead of a character count.
129  */
130 #define LOG_DISPATCHER(fn) int (fn)(char *message, sza::array::LogStream id, void *context, unsigned seq, bool isEnd)
131 
132 /*
133  * The following function registers a function to be called to process
134  * the lprintf() line-buffered output of stdout and stderr. To revert
135  * the specified stream to fprintf(), send log_fn=0. In order to allow
136  * nesting of calls to divert_lprintf(), if the old_fn and old_context
137  * arguments are both non-NULL, then any previous dispatch function
138  * and its context will be assigned to them. The caller can then
139  * reinstall them if needed.
140  */
141 int divert_lprintf(FILE *stream, LOG_DISPATCHER(*log_fn), void *context,
142  LOG_DISPATCHER(**old_fn), void **old_context);
143 
144 #endif