File: debug.cxx

package info (click to toggle)
curves 0.8.7
  • links: PTS
  • area: main
  • in suites: slink
  • size: 704 kB
  • ctags: 1,001
  • sloc: cpp: 6,197; ansic: 519; makefile: 270; sh: 192; fortran: 149
file content (272 lines) | stat: -rw-r--r-- 8,654 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
/* debug.cxx
     $Id: debug.cxx,v 1.13 1998/06/22 06:21:35 elf Exp $

   written by Marc Singer
   20 October 1996

   This file is part of the project CurVeS.  See the file README for
   more information.

   Copyright (C) 1996 Marc Singer

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   in a file called COPYING along with this program; if not, write to
   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
   02139, USA.

   -----------
   DESCRIPTION
   -----------

   Here we control all of the debug functions.  We define our own
   assertion handling, trace code, and some helper code for gross
   profiling. 

   -- Syslog Socket logging

   As of sysklogd-1.3 for Linux, the udp logging is disabled by
   default.  The syslogd requires a switch (-r) to enable reading of
   syslog messages from the udp service port 514.

   We send our messages to the local0 facility.  The debugSeverity
   setting controls the severity with which we log.  

     debugSeverityInfo    -> local0.info
     debugSeverityDebug   -> local0.debug
     debugSeverityWarning -> local0.warn
     debugSeverityError   -> local0.err
     debugSeverityFatal   -> local0.crit

*/


#include "std.h"
#include "preferences.h"	// Everyone MUST get into the pref scene

#include <stdarg.h>
#include <syslog.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>

#include "debug.h"			// Redundant, actually

//#define USE_TRACE_STDERR		// fprintf's to STDERR, not very useful
//#define USE_TRACE_SYSLOG		// Syslog via UNIX domain socket file
#define USE_TRACE_SYSLOG_SOCKET		// Syslog via internet sockets
//#define USE_TRACE_LISTEN_SOCKET		// Our own listen tool

#if   defined (USE_TRACE_LISTEN_SOCKET)
# define PORT_TRACE (2112)			// Port: listen
#elif defined (USE_TRACE_SYSLOG_SOCKET)
# define PORT_TRACE (514)			// Port: syslog
#endif

#define ADDR_TRACE (0x7f000001)			// Address: loopback


int g_maskTrace = 0;		// Bits controlling what gets Traced
extern char* g_szProgram;	// Name of program from command line
static struct timeval g_timevalPrevious; // Last timestamp


/* __assert

   handles assertion failures.  The reson to use our own handler is
   that we know we can break on it and we know, too, that we can
   handle it the way we want to.  Not all environments permit us to
   continue after an assertion.  We may include the ability of a
   caller to include a special action button (metaphorically such)
   procedure in case there is some cleanup, or perhaps bug processing
   information to collect.

*/

void __assert (const char* szExpression, const char* szFile, int line)
{
  fprintf (stderr, "\r\nassertion failed (%s) in %s line %d [ac] ", 
	   szExpression, szFile, line);
  char ch;
  while (((ch = fgetc (stdin)), ch = tolower (ch)) != 'a' && ch != 'c')
    ;
  if (ch == 'a') {
    fprintf (stderr, "\r\n");
    exit (-1);
  }
}


/* __trace

   emit message to selected debug stream.  Trace can use one of
   several different debug stream types in order to support systems
   with and without syslogd.  Each message is selected by the code
   parameter which is the or'ing of a debugSeverity and debugClass
   values.  The g_maskTrace static variable will filter messages that
   don't meet it's criteria.

   Trace accepts a vararg list and does an sprintf on it.  We have a
   static buffer, so be considerate since there is no vnsprintf in
   standard libc's.  We append a newline when necessary, so you don't
   need to do so when calling Trace.

   To use Trace, use the macro TRACE() that can be compiled out, if we
   choose:

     TRACE((code, "There are %d little piggies", cPiggies));

   The double parenthesis are what allow us to macroize T into
   nothingness AND have a variable number of arguments. 

*/

void __trace (int code, const char* sz, ...)
{
  if (g_maskTrace == 1)
    g_maskTrace |= debugSeverityTrace; 	// Special, default hack enables Trace

  if (!(g_maskTrace & debugEnable))
    return;
  if (code && (code & g_maskTrace) != code)
    return;

  int priority = 0;
  const char* szOutput = g_preferences.fetch ("DebugOutput");
  if (strncmp (szOutput, "local", 5) == 0) {
    int i = atoi (szOutput + 5);
    switch (i) {
    case 0: priority = LOG_LOCAL0; break;
    case 1: priority = LOG_LOCAL1; break;
    case 2: priority = LOG_LOCAL2; break;
    case 3: priority = LOG_LOCAL3; break;
    case 4: priority = LOG_LOCAL4; break;
    case 5: priority = LOG_LOCAL5; break;
    case 6: priority = LOG_LOCAL6; break;
    case 7: priority = LOG_LOCAL7; break;
    default: return;
    }
  }

  static char szMsg[1024];
  int cchPrefix = 0;

  if (priority) {
    switch (code & debugSeverityMask) {
    default:
    case debugSeverityInfo:    priority |= LOG_INFO;    break;
    case debugSeverityTrace:   priority |= LOG_DEBUG;   break;
    case debugSeverityWarning: priority |= LOG_WARNING; break;
    case debugSeverityError:   priority |= LOG_ERR;     break;
    case debugSeverityFatal:   priority |= LOG_CRIT;    break;
    }
    cchPrefix = sprintf (szMsg, "<%d>", priority);
  }
  else {
    switch (code & debugSeverityMask) {
    default:
    case debugSeverityInfo:    strcpy (szMsg, "in "); break;
    case debugSeverityTrace:   strcpy (szMsg, "tr "); break;
    case debugSeverityWarning: strcpy (szMsg, "wn "); break;
    case debugSeverityError:   strcpy (szMsg, "er "); break;
    case debugSeverityFatal:   strcpy (szMsg, "fa "); break;
    }
    cchPrefix = 3;
  }

  int cch = 0;

  const char* szTimeOption = g_preferences.fetch ("DebugTimestamps");
  if (szTimeOption && strcasecmp (szTimeOption, "none")) {
    struct timeval timeval;
    gettimeofday (&timeval, NULL);
    time_t time = timeval.tv_sec;

    if (!strcasecmp (szTimeOption, "tod")) {
      struct tm* ptm = localtime (&time);
      cch += sprintf (szMsg + cch + cchPrefix, "%02d:%02d:%02d.%03ld ", 
		      ptm->tm_hour, ptm->tm_min, ptm->tm_sec, 
		      int32 (timeval.tv_usec/1000));
    }
    else if (!strcasecmp (szTimeOption, "relative")) {
      if (!g_timevalPrevious.tv_sec) 			// Initial case
	g_timevalPrevious = timeval;
      int s = timeval.tv_sec - g_timevalPrevious.tv_sec;
      int us = timeval.tv_usec - g_timevalPrevious.tv_usec;
      if (us < 0) {
	us += 1000000;
	s -= 1;
      }
      if (s > 60)
	cch += sprintf (szMsg + cch + cchPrefix, "%02d:%02d:%02d.%03d ", 
			(s/(60*60))%24, (s/60)%60, s%60, us/1000);
      else
	cch += sprintf (szMsg + cch + cchPrefix, "%02d.%03d ", s, us/1000);
      g_timevalPrevious = timeval;
    }
  }

  cch += sprintf (szMsg + cch + cchPrefix, "%s: ", g_szProgram);

  va_list ap;
  va_start (ap, sz);
  cch += vsnprintf (szMsg + cch + cchPrefix, 
		    sizeof (szMsg) - cch - cchPrefix, sz, ap);
  va_end (ap);

  if (!priority && cch && szMsg[cchPrefix + cch - 1] != '\n') {
//    szMsg[cchPrefix + cch++] = '\r'; // ** FIXME why was this here?
    szMsg[cchPrefix + cch++] = '\n';
    szMsg[cchPrefix + cch] = 0;
  }    

#if defined (USE_TRACE_SYSLOG_SOCKET) || defined (USE_TRACE_LISTEN_SOCKET)
  if (priority) {
    int socket = ::socket (AF_INET, SOCK_DGRAM, 17); // UDP
    struct sockaddr_in addr;
    memset (&addr, 0, sizeof (addr));
    addr.sin_family = AF_INET;
    int result = bind (socket, (const struct sockaddr*) &addr, sizeof (addr));
    if (!result) {
      addr.sin_family		= AF_INET;
      addr.sin_port		= htons (PORT_TRACE);
      addr.sin_addr.s_addr	= htonl (ADDR_TRACE);
      result = connect (socket, (const struct sockaddr*) &addr, sizeof (addr));
      if (!result)
	send (socket, szMsg, cchPrefix + cch + 1, 0);
    }
    close (socket);
  }
#endif

#if defined (USE_TRACE_SYSLOG)
  if (priority) {
    /* As of last testing, syslogd-1.3 does not support this socket file. */
    int fh = open ("/dev/log", O_WRONLY);
    if (fh != -1)
      write (fh, szMsg, cch + cchPrefix + 1);
    close (fh);
  }
#endif

#if defined (USE_TRACE_STDERR)
  fprintf (stderr, szMsg + cchPrefix);
#endif
  
  if (!priority) {
    int fh = open (szOutput, O_WRONLY | O_APPEND | O_CREAT, 0666);
    if (fh != -1) {
      write (fh, szMsg, strlen (szMsg));
      close (fh);
    }
  }
}