BRL-CAD
log.c
Go to the documentation of this file.
1 /* L O G . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2004-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 
21 #include "common.h"
22 
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <string.h>
27 #include <stdarg.h>
28 
29 #include "bu/log.h"
30 #include "bu/parallel.h"
31 
32 
33 /**
34  * list of callbacks to call during bu_log.
35  *
36  * NOT published in a public header.
37  */
38 static struct bu_hook_list log_hook_list = {
39  {
41  &log_hook_list.l,
42  &log_hook_list.l
43  },
44  NULL,
45  ((void *)0)
46 };
47 
48 static int log_first_time = 1;
49 static int log_hooks_called = 0;
50 static int log_indent_level = 0;
51 
52 
53 void
55 {
56  if ((log_indent_level += delta) < 0)
57  log_indent_level = 0;
58 }
59 
60 
61 void
63 {
64  bu_vls_spaces(v, log_indent_level);
65 }
66 
67 
68 void
70 {
71  bu_hook_add(&log_hook_list, func, clientdata);
72 }
73 
74 
75 void
77 {
78  bu_hook_delete(&log_hook_list, func, clientdata);
79 }
80 
81 HIDDEN void
82 log_call_hooks(void *buf)
83 {
84 
85  log_hooks_called = 1;
86  bu_hook_call(&log_hook_list, buf);
87  log_hooks_called = 0;
88 }
89 
90 
91 void
93 {
94  bu_hook_save_all(&log_hook_list, save_hlp);
95 }
96 
97 
98 void
100 {
101  bu_hook_delete_all(&log_hook_list);
102 }
103 
104 
105 void
107 {
108  bu_hook_restore_all(&log_hook_list, restore_hlp);
109 }
110 
111 
112 /**
113  * This subroutine is used to append log_indent_level spaces
114  * into a printf() format specifier string, after each newline
115  * character is encountered.
116  *
117  * It exists primarily for bu_shootray() to affect the indentation
118  * level of all messages at that recursion level, even if the calls
119  * to bu_log come from non-librt routines.
120  */
121 HIDDEN void
122 log_do_indent_level(struct bu_vls *new_vls, register const char *old_vls)
123 {
124  register int i;
125 
126  while (*old_vls) {
127  bu_vls_putc(new_vls, (int)(*old_vls));
128  if (*old_vls == '\n') {
129  i = log_indent_level;
130  while (i-- > 0)
131  bu_vls_putc(new_vls, ' ');
132  }
133  ++old_vls;
134  }
135 }
136 
137 
138 void
140 {
141  int ret = EOF;
142 
143  if (BU_LIST_IS_EMPTY(&(log_hook_list.l))) {
144 
145  if (LIKELY(stderr != NULL)) {
146  ret = fputc(c, stderr);
147  }
148 
149  if (UNLIKELY(ret == EOF && stdout)) {
150  ret = fputc(c, stdout);
151  }
152 
153  if (UNLIKELY(ret == EOF)) {
154  bu_bomb("bu_putchar: write error");
155  }
156 
157  } else {
158  char buf[2];
159  buf[0] = (char)c;
160  buf[1] = '\0';
161 
162  log_call_hooks(buf);
163  }
164 
165  if (log_indent_level > 0 && c == '\n') {
166  int i;
167 
168  i = log_indent_level;
169  while (i-- > 0)
170  bu_putchar(' ');
171  }
172 }
173 
174 
175 void
176 bu_log(const char *fmt, ...)
177 {
178  va_list ap;
179  struct bu_vls output = BU_VLS_INIT_ZERO;
180 
181  if (UNLIKELY(!fmt || strlen(fmt) == 0)) {
182  bu_vls_free(&output);
183  return;
184  }
185 
186  va_start(ap, fmt);
187 
188  if (log_indent_level > 0) {
189  struct bu_vls newfmt = BU_VLS_INIT_ZERO;
190 
191  log_do_indent_level(&newfmt, fmt);
192  bu_vls_vprintf(&output, bu_vls_addr(&newfmt), ap);
193  bu_vls_free(&newfmt);
194  } else {
195  bu_vls_vprintf(&output, fmt, ap);
196  }
197 
198  va_end(ap);
199 
200  if (BU_LIST_IS_EMPTY(&(log_hook_list.l)) || log_hooks_called) {
201  size_t ret = 0;
202  size_t len;
203 
204  if (UNLIKELY(log_first_time)) {
205  bu_setlinebuf(stderr);
206  log_first_time = 0;
207  }
208 
209  len = bu_vls_strlen(&output);
210  if (UNLIKELY(len <= 0)) {
211  bu_vls_free(&output);
212  return;
213  }
214 
215  if (LIKELY(stderr != NULL)) {
217  ret = fwrite(bu_vls_addr(&output), len, 1, stderr);
218  fflush(stderr);
220  }
221 
222  if (UNLIKELY(ret == 0 && stdout)) {
223  /* if stderr fails, try stdout instead */
225  ret = fwrite(bu_vls_addr(&output), len, 1, stdout);
226  fflush(stdout);
228  }
229 
230  if (UNLIKELY(ret == 0)) {
232  perror("fwrite failed");
234  bu_bomb("bu_log: write error");
235  }
236 
237  } else {
238  log_call_hooks(bu_vls_addr(&output));
239  }
240 
241  bu_vls_free(&output);
242 }
243 
244 
245 void
246 bu_flog(FILE *fp, const char *fmt, ...)
247 {
248  va_list ap;
249 
250  struct bu_vls output = BU_VLS_INIT_ZERO;
251 
252  va_start(ap, fmt);
253  if (log_indent_level > 0) {
254  struct bu_vls newfmt = BU_VLS_INIT_ZERO;
255 
256  log_do_indent_level(&newfmt, fmt);
257  bu_vls_vprintf(&output, bu_vls_addr(&newfmt), ap);
258  bu_vls_free(&newfmt);
259  } else {
260  bu_vls_vprintf(&output, fmt, ap);
261  }
262 
263  if (BU_LIST_IS_EMPTY(&(log_hook_list.l)) || log_hooks_called) {
264  size_t ret;
265  size_t len;
266 
267  len = bu_vls_strlen(&output);
268  if (LIKELY(len)) {
270  ret = fwrite(bu_vls_addr(&output), len, 1, fp);
272 
273  if (UNLIKELY(ret != 1))
274  bu_bomb("bu_flog: write error");
275  }
276 
277  } else {
278  log_call_hooks(bu_vls_addr(&output));
279  }
280 
281  va_end(ap);
282 
283  bu_vls_free(&output);
284 }
285 
286 
287 /*
288  * Local Variables:
289  * mode: C
290  * tab-width: 8
291  * indent-tabs-mode: t
292  * c-file-style: "stroustrup"
293  * End:
294  * ex: shiftwidth=4 tabstop=8
295  */
void bu_log_add_hook(bu_hook_t func, void *clientdata)
Definition: log.c:69
void bu_log(const char *fmt,...)
Definition: log.c:176
void bu_log_hook_save_all(struct bu_hook_list *save_hlp)
Definition: log.c:92
void bu_hook_save_all(struct bu_hook_list *hlp, struct bu_hook_list *save_hlp)
Definition: hook.c:82
#define LIKELY(expression)
Definition: common.h:261
void bu_semaphore_acquire(unsigned int i)
Definition: semaphore.c:180
void bu_hook_add(struct bu_hook_list *hlp, bu_hook_t func, void *clientdata)
Definition: hook.c:39
#define BU_LIST_IS_EMPTY(hp)
Definition: list.h:295
void bu_log_indent_vls(struct bu_vls *v)
Definition: log.c:62
void * clientdata
Definition: log.h:73
Header file for the BRL-CAD common definitions.
void bu_log_indent_delta(int delta)
Definition: log.c:54
#define HIDDEN
Definition: common.h:86
void bu_vls_free(struct bu_vls *vp)
Definition: vls.c:248
void bu_putchar(int c)
Definition: log.c:139
void bu_hook_restore_all(struct bu_hook_list *hlp, struct bu_hook_list *restore_hlp)
Definition: hook.c:108
struct bu_list l
Definition: log.h:71
void bu_log_hook_delete_all()
Definition: log.c:99
HIDDEN void log_call_hooks(void *buf)
Definition: log.c:82
size_t bu_vls_strlen(const struct bu_vls *vp)
Definition: vls.c:189
void bu_hook_call(struct bu_hook_list *hlp, void *buf)
Definition: hook.c:68
void bu_log_hook_restore_all(struct bu_hook_list *restore_hlp)
Definition: log.c:106
char * bu_vls_addr(const struct bu_vls *vp)
Definition: vls.c:111
void bu_vls_vprintf(struct bu_vls *vls, const char *fmt, va_list ap)
Definition: vls_vprintf.c:380
void bu_semaphore_release(unsigned int i)
Definition: semaphore.c:218
#define BU_SEM_SYSCALL
Definition: parallel.h:178
int(* bu_hook_t)(void *, void *)
Definition: log.h:68
void bu_hook_delete(struct bu_hook_list *hlp, bu_hook_t func, void *clientdata)
Definition: hook.c:52
void bu_hook_delete_all(struct bu_hook_list *hlp)
Definition: hook.c:96
void bu_vls_spaces(struct bu_vls *vp, size_t cnt)
Definition: vls.c:721
#define BU_VLS_INIT_ZERO
Definition: vls.h:84
#define BU_LIST_HEAD_MAGIC
Definition: magic.h:56
Definition: vls.h:56
void bu_setlinebuf(FILE *fp)
Definition: linebuf.c:44
void bu_bomb(const char *str) _BU_ATTR_NORETURN
Definition: bomb.c:91
HIDDEN const point_t delta
Definition: sh_prj.c:618
void bu_vls_putc(struct bu_vls *vp, int c)
Definition: vls.c:666
HIDDEN void log_do_indent_level(struct bu_vls *new_vls, register const char *old_vls)
Definition: log.c:122
void bu_flog(FILE *fp, const char *fmt,...)
Definition: log.c:246
void bu_log_delete_hook(bu_hook_t func, void *clientdata)
Definition: log.c:76
#define UNLIKELY(expression)
Definition: common.h:282