log.c

Go to the documentation of this file.
00001 /*                           L O G . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 2004-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** \addtogroup bu_log */
00023 /*@{*/
00024 /** @file log.c
00025  * @brief parallel safe version of fprintf for logging
00026  *
00027  *  BRL-CAD support library, error logging routine.
00028  *  Note that the user may provide his own logging routine,
00029  *  by replacing these functions.  That is why this is in file of it's own.
00030  *  For example, LGT and RTSRV take advantage of this.
00031  *
00032  * @par  Primary Functions (replacements MUST implement all these) -
00033  * @n   bu_log                  Called to log library events.
00034  * @n   bu_log_indent_delta     Change global indentation level
00035  * @n   bu_log_indent_vls       Apply indentation level (used by librt/pr.c)
00036  *
00037  * @par Specialty Functions -
00038  *      bu_log_add_hook         Start catching log events (used by mged/cmd.c)
00039  * @n   bu_putchar
00040  *
00041  *  @author     Michael John Muuss
00042  *  @author     Glenn Durfee
00043  *
00044  * @par  Source -
00045  *      The U. S. Army Research Laboratory
00046  * @n   Aberdeen Proving Ground, Maryland  21005-5068  USA
00047  */
00048 
00049 #ifndef lint
00050 static const char RCSlog[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/libbu/log.c,v 14.12 2006/09/03 15:14:07 lbutler Exp $ (ARL)";
00051 #endif
00052 
00053 #include "common.h"
00054 
00055 #include <stdio.h>
00056 #include <ctype.h>
00057 #if defined(HAVE_STDARG_H)
00058 # include <stdarg.h>
00059 #else
00060 #  if defined(HAVE_VARARGS_H)
00061 #    include <varargs.h>
00062 #  endif
00063 #endif
00064 #ifdef HAVE_STRING_H
00065 #  include <string.h>
00066 #endif
00067 
00068 #include "machine.h"
00069 #include "bu.h"
00070 
00071 #if defined(HAVE_VARARGS_H) || defined(HAVE_STDARG_H)
00072 BU_EXTERN(void  bu_vls_vprintf, (struct bu_vls *vls, const char *fmt, va_list ap));
00073 #endif
00074 
00075 static int      bu_log_indent_cur_level = 0; /* formerly rt_g.rtg_logindent */
00076 /**
00077  *                      B U _ L O G _ I N D E N T _ D E L T A
00078  *
00079  *  Change indentation level by indicated number of characters.
00080  *  Call with a large negative number to cancel all indentation.
00081  */
00082 void
00083 bu_log_indent_delta(int delta)
00084 {
00085         if( (bu_log_indent_cur_level += delta) < 0 )
00086                 bu_log_indent_cur_level = 0;
00087 }
00088 
00089 /**
00090  *                      B U _ L O G _ I N D E N T _ V L S
00091  *
00092  *  For multi-line vls generators, honor logindent level like bu_log() does,
00093  *  and prefix the proper number of spaces.
00094  *  Should be called at the front of each new line.
00095  */
00096 void
00097 bu_log_indent_vls(struct bu_vls *v)
00098 {
00099         bu_vls_spaces( v, bu_log_indent_cur_level );
00100 }
00101 
00102 #if 1
00103 struct bu_hook_list bu_log_hook_list = {
00104         {       BU_LIST_HEAD_MAGIC,
00105                 &bu_log_hook_list.l,
00106                 &bu_log_hook_list.l
00107         },
00108         BUHOOK_NULL,
00109         GENPTR_NULL
00110 };
00111 #else
00112 struct bu_hook_list bu_log_hook_list;
00113 #endif
00114 
00115 static int bu_log_first_time = 1;
00116 static int bu_log_hooks_called = 0;
00117 
00118 /**
00119  *                      B U _ L O G _ A D D _ H O O K
00120  *
00121  *  Adds a hook to the list of bu_log hooks.  The top (newest) one of these
00122  *  will be called with its associated client data and a string to be
00123  *  processed.  Typcially, these hook functions will display the output
00124  *  (possibly in an X window) or record it.
00125  *
00126  *  XXX The hook functions are all non-PARALLEL.
00127  */
00128 
00129 void
00130 bu_log_add_hook(bu_hook_t func, genptr_t clientdata)
00131 {
00132 #if 0
00133     struct bu_hook_list *toadd;
00134 
00135     /* Grab a hunk of memory for a new node, and put it at the head of the
00136        list */
00137 
00138     BU_GETSTRUCT(toadd, bu_hook_list);
00139     toadd->hookfunc = func;
00140     toadd->clientdata = clientdata;
00141     toadd->l.magic = BUHOOK_LIST_MAGIC;
00142 
00143     BU_LIST_APPEND( &(bu_log_hook_list.l), &(toadd->l) );
00144 #else
00145     bu_add_hook(&bu_log_hook_list, func, clientdata);
00146 #endif
00147 }
00148 
00149 
00150 /**
00151  *                      B U _ L O G _ D E L E T E _ H O O K
00152  *
00153  *  Removes the hook matching the function and clientdata parameters from
00154  *  the hook list.  Note that it is not necessarily the active (top) hook.
00155  */
00156 void
00157 bu_log_delete_hook(bu_hook_t func, genptr_t clientdata)
00158 {
00159 #if 0
00160     struct bu_hook_list *cur = &bu_log_hook_list;
00161 
00162     for ( BU_LIST_FOR( cur, bu_hook_list, &(bu_log_hook_list.l) ) ) {
00163         if ( cur->hookfunc == func && cur->clientdata == clientdata) {
00164             struct bu_hook_list *old = BU_LIST_PLAST(bu_hook_list, cur);
00165             BU_LIST_DEQUEUE( &(cur->l) );
00166             bu_free((genptr_t)cur, "bu_log hook");
00167             cur = old;
00168         }
00169     }
00170 #else
00171     bu_delete_hook(&bu_log_hook_list, func, clientdata);
00172 #endif
00173 }
00174 
00175 #if 1
00176 HIDDEN void
00177 bu_log_call_hooks(genptr_t buf)
00178 {
00179 #if 0
00180     bu_hook_t hookfunc;         /* for clarity */
00181     genptr_t clientdata;
00182 #endif
00183 
00184     bu_log_hooks_called = 1;
00185 
00186 #if 0
00187     hookfunc = BU_LIST_FIRST(bu_hook_list, &(bu_log_hook_list.l))->hookfunc;
00188     clientdata = BU_LIST_FIRST(bu_hook_list, &(bu_log_hook_list.l))->clientdata;
00189 
00190     (hookfunc)( clientdata, buf);
00191 #else
00192     bu_call_hook(&bu_log_hook_list, buf);
00193 #endif
00194 
00195     bu_log_hooks_called = 0;
00196 }
00197 #endif
00198 
00199 /**
00200  *                      B U _ L O G _ D O _ I N D E N T _ L E V E L
00201  *
00202  *  This subroutine is used to append bu_log_indent_cur_level spaces
00203  *  into a printf() format specifier string, after each newline
00204  *  character is encountered.
00205  *  It exists primarily for bu_shootray() to affect the indentation
00206  *  level of all messages at that recursion level, even if the calls
00207  *  to bu_log come from non-librt routines.
00208  */
00209 
00210 HIDDEN void
00211 bu_log_do_indent_level(struct bu_vls *new, register char *old)
00212 {
00213     register int i;
00214 
00215     while (*old) {
00216         bu_vls_putc(new, (int)(*old));
00217         if (*old == '\n') {
00218             i = bu_log_indent_cur_level;
00219             while (i-- > 0)
00220                 bu_vls_putc(new, ' ');
00221         }
00222         ++old;
00223     }
00224 }
00225 
00226 /**
00227  *                      B U _ P U T C H A R
00228  *
00229  * Log a single character with no flushing.
00230  */
00231 
00232 void
00233 bu_putchar(int c)
00234 {
00235     if ( BU_LIST_IS_EMPTY( &(bu_log_hook_list.l) ) ) {
00236         fputc(c, stderr);
00237     } else {
00238         char buf[2];
00239         buf[0] = (char)c;
00240         buf[1] = '\0';
00241 #if 1
00242         bu_log_call_hooks(buf);
00243 #else
00244         bu_call_hook(&bu_log_hook_list, (genptr_t)buf);
00245 #endif
00246     }
00247 
00248     if (bu_log_indent_cur_level > 0 && c == '\n') {
00249         int i;
00250 
00251         i = bu_log_indent_cur_level;
00252         while (i-- > 0)
00253             bu_putchar(' ');
00254     }
00255 }
00256 
00257 /**
00258  *                      B U _ L O G
00259  *
00260  *  Log a library event in the Standard way.
00261  */
00262 void
00263 #if defined(HAVE_STDARG_H)
00264 bu_log(char *fmt, ...)                      /* ANSI C */
00265 {
00266     va_list ap;
00267 #else
00268 #  if defined(HAVE_VARARGS_H)
00269 bu_log(va_alist)                            /* VARARGS */
00270 va_dcl
00271 {
00272     va_list ap;
00273     char *fmt;
00274 #  else
00275 bu_log(fmt, a,b,c,d,e,f,g,h,i,j)            /* Cray XMP */
00276 char *fmt;
00277 {
00278 #  endif
00279 #endif
00280 
00281     struct bu_vls output;
00282 
00283     bu_vls_init(&output);
00284 
00285 #if defined(HAVE_STDARG_H)                  /* ANSI C */
00286     va_start(ap, fmt);
00287 
00288     if (!fmt || strlen(fmt) == 0) {
00289         return;
00290     }
00291 
00292     if (bu_log_indent_cur_level > 0) {
00293         struct bu_vls newfmt;
00294 
00295         bu_vls_init(&newfmt);
00296         bu_log_do_indent_level(&newfmt, fmt);
00297         bu_vls_vprintf(&output, bu_vls_addr(&newfmt), ap);
00298         bu_vls_free(&newfmt);
00299     } else {
00300         bu_vls_vprintf(&output, fmt, ap);   /* VARARGS */
00301     }
00302 #else
00303 #  if defined(HAVE_VARARGS_H)
00304     va_start(ap);
00305     fmt = va_arg(ap, char *);
00306 
00307     if (!fmt || strlen(fmt) == 0) {
00308         return;
00309     }
00310 
00311     if (bu_log_indent_cur_level > 0) {
00312         struct bu_vls newfmt;
00313 
00314         bu_vls_init(&newfmt);
00315         bu_log_do_indent_level(&newfmt, fmt);
00316         bu_vls_vprintf(&output, bu_vls_addr(&newfmt), ap);
00317         bu_vls_free(&newfmt);
00318     } else {
00319         bu_vls_vprintf(&output, fmt, ap);
00320     }
00321 #  else                                     /* Cray XMP */
00322     if (!fmt || strlen(fmt) == 0) {
00323         return;
00324     }
00325 
00326     if (bu_log_indent_cur_level > 0) {
00327         struct bu_vls newfmt;
00328 
00329         bu_vls_init(&newfmt);
00330         bu_log_do_indent_level(&newfmt, fmt);
00331         bu_vls_printf(&output, bu_vls_addr(&newfmt), a,b,c,d,e,f,g,h,i,j);
00332         bu_vls_free(&newfmt);
00333     } else {
00334         bu_vls_printf(&output, fmt, a,b,c,d,e,f,g,h,i,j);
00335     }
00336 #  endif
00337 #endif
00338 
00339     if ( BU_LIST_IS_EMPTY( &(bu_log_hook_list.l) )  || bu_log_hooks_called) {
00340         int ret;
00341         size_t len;
00342 
00343         if (bu_log_first_time) {
00344             bu_setlinebuf(stderr);
00345             bu_log_first_time = 0;
00346         }
00347 
00348         len = bu_vls_strlen(&output);
00349         if(len){
00350           bu_semaphore_acquire(BU_SEM_SYSCALL);
00351           ret = fwrite( bu_vls_addr(&output), len, 1, stderr );
00352           (void)fflush(stderr);
00353           bu_semaphore_release(BU_SEM_SYSCALL);
00354           if( ret != 1 )  bu_bomb("bu_log: write error");
00355         }
00356 
00357     } else {
00358 #if 1
00359             bu_log_call_hooks(bu_vls_addr(&output));
00360 #else
00361             bu_call_hook(&bu_log_hook_list, (genptr_t)bu_vls_addr(&output));
00362 #endif
00363     }
00364 
00365 #if defined(HAVE_STDARG_H) || defined(HAVE_VARARGS_H)
00366     va_end(ap);
00367 #endif
00368 
00369     bu_vls_free(&output);
00370 }
00371 
00372 /**
00373  *                      B U _ F L O G
00374  *
00375  *  Log a library event in the Standard way, to a specified file.
00376  */
00377 void
00378 #if defined(HAVE_STDARG_H)
00379 bu_flog(FILE *fp, char *fmt, ...)                      /* ANSI C */
00380 {
00381     va_list ap;
00382 #else
00383 #  if defined(HAVE_VARARGS_H)
00384 bu_flog(va_alist)                            /* VARARGS */
00385 va_dcl
00386 {
00387     va_list ap;
00388     FILE *fp;
00389     char *fmt;
00390 #  else
00391 bu_flog(fp, fmt, a,b,c,d,e,f,g,h,i,j)            /* Cray XMP */
00392 FILE *fp;
00393 char *fmt;
00394 {
00395 #  endif
00396 #endif
00397 
00398     struct bu_vls output;
00399 
00400     bu_vls_init(&output);
00401 
00402 #if defined(HAVE_STDARG_H)                  /* ANSI C */
00403     va_start(ap, fmt);
00404     if (bu_log_indent_cur_level > 0) {
00405         struct bu_vls newfmt;
00406 
00407         bu_vls_init(&newfmt);
00408         bu_log_do_indent_level(&newfmt, fmt);
00409         bu_vls_vprintf(&output, bu_vls_addr(&newfmt), ap);
00410         bu_vls_free(&newfmt);
00411     } else {
00412         bu_vls_vprintf(&output, fmt, ap);   /* VARARGS */
00413     }
00414 #else
00415 #  if defined(HAVE_VARARGS_H)
00416     va_start(ap);
00417     fp = va_arg(ap, FILE *);
00418     fmt = va_arg(ap, char *);
00419     if (bu_log_indent_cur_level > 0) {
00420         struct bu_vls newfmt;
00421 
00422         bu_vls_init(&newfmt);
00423         bu_log_do_indent_level(&newfmt, fmt);
00424         bu_vls_vprintf(&output, bu_vls_addr(&newfmt), ap);
00425         bu_vls_free(&newfmt);
00426     } else {
00427         bu_vls_vprintf(&output, fmt, ap);
00428     }
00429 #  else                                     /* Cray XMP */
00430     if (bu_log_indent_cur_level > 0) {
00431         struct bu_vls newfmt;
00432 
00433         bu_vls_init(&newfmt);
00434         bu_log_do_indent_level(&newfmt, fmt);
00435         bu_vls_printf(&output, bu_vls_addr(&newfmt), a,b,c,d,e,f,g,h,i,j);
00436         bu_vls_free(&newfmt);
00437     } else {
00438         bu_vls_printf(&output, fmt, a,b,c,d,e,f,g,h,i,j);
00439     }
00440 #  endif
00441 #endif
00442 
00443     if ( BU_LIST_IS_EMPTY( &(bu_log_hook_list.l) ) || bu_log_hooks_called) {
00444         int ret;
00445         size_t len;
00446 
00447         len = bu_vls_strlen(&output);
00448         if(len){
00449           bu_semaphore_acquire(BU_SEM_SYSCALL);
00450           ret = fwrite( bu_vls_addr(&output), len, 1, fp );
00451           bu_semaphore_release(BU_SEM_SYSCALL);
00452           if( ret != 1 )  bu_bomb("bu_flog: write error");
00453         }
00454 
00455     } else {
00456 #if 1
00457             bu_log_call_hooks(bu_vls_addr(&output));
00458 #else
00459             bu_call_hook(&bu_log_hook_list, (genptr_t)bu_vls_addr(&output));
00460 #endif
00461     }
00462 
00463 #if defined(HAVE_STDARG_H) || defined(HAVE_VARARGS_H)
00464     va_end(ap);
00465 #endif
00466 
00467     bu_vls_free(&output);
00468 }
00469 
00470 /*@}*/
00471 
00472 /*
00473  * Local Variables:
00474  * mode: C
00475  * tab-width: 8
00476  * c-basic-offset: 4
00477  * indent-tabs-mode: t
00478  * End:
00479  * ex: shiftwidth=4 tabstop=8
00480  */

Generated on Mon Sep 18 01:24:48 2006 for BRL-CAD by  doxygen 1.4.6