Coverage Report

Created: 2026-01-04 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/netcdf-c/libdispatch/nclog.c
Line
Count
Source
1
/*********************************************************************
2
 *   Copyright 2018, UCAR/Unidata
3
 *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4
 *   $Header$
5
 *********************************************************************/
6
7
#include "config.h"
8
#ifdef _MSC_VER
9
#include<io.h>
10
#endif
11
12
#include <stdlib.h>
13
#include <stdio.h>
14
#include <stdarg.h>
15
#include <string.h>
16
#include <errno.h>
17
#ifdef HAVE_FCNTL_H
18
#include <fcntl.h>
19
#endif
20
#ifdef HAVE_UNISTD_H
21
#include <unistd.h>
22
#endif
23
 
24
#include "netcdf.h"
25
#include "nclog.h"
26
27
#define PREFIXLEN 8
28
#define MAXTAGS 256
29
#define NCTAGDFALT "Log";
30
31
#define NC_MAX_FRAMES 1024
32
33
static int nclogginginitialized = 0;
34
35
static struct NCLOGGLOBAL {
36
    int loglevel;
37
    int tracelevel;
38
    FILE* nclogstream;
39
    int depth;
40
    struct Frame {
41
  const char* fcn;
42
  int level;
43
  int depth;
44
    } frames[NC_MAX_FRAMES];
45
} nclog_global = {0,-1,NULL};
46
47
static const char* nctagset[] = {"OFF","ERR","WARN","NOTE","DEBUG",NULL};
48
49
/* Forward */
50
static const char* nctagname(int tag);
51
static int nctagforname(const char* tag);
52
/*!\defgroup NClog NClog Management
53
@{*/
54
55
/*!\internal
56
*/
57
58
void
59
ncloginit(void)
60
1
{
61
1
    const char* envv = NULL;
62
1
    if(nclogginginitialized)
63
0
  return;
64
1
    nclogginginitialized = 1;
65
1
    memset(&nclog_global,0,sizeof(nclog_global));
66
1
    ncsetloglevel(NCLOGOFF);
67
1
    nclog_global.tracelevel = -1;    
68
1
    nclog_global.nclogstream = stderr;
69
    /* Use environment variables to preset nclogging state*/
70
1
    envv = getenv(NCENVLOGGING);
71
1
    if(envv != NULL) {
72
0
  int level = nctagforname(envv);
73
0
        if(level > 0) {
74
0
            ncsetloglevel(NCLOGNOTE);
75
0
        }
76
0
    }
77
1
    envv = getenv(NCENVTRACING);
78
1
    if(envv != NULL) nctracelevel(atoi(envv));
79
1
}
80
81
/*!
82
Enable logging messages to a given level. Set to NCLOGOFF to disable
83
all messages, NCLOGERR for errors only, NCLOGWARN for warnings and
84
errors, and so on
85
86
\param[in] level Messages above this level are ignored
87
88
\return The previous value of the logging flag.
89
*/
90
91
int
92
ncsetloglevel(int level)
93
1
{
94
1
    int was;
95
1
    if(!nclogginginitialized) ncloginit();
96
1
    was = nclog_global.loglevel;
97
1
    if(level >= 0 && level <= NCLOGDEBUG)
98
1
  nclog_global.loglevel = level;
99
1
    if(nclog_global.nclogstream == NULL) nclogopen(NULL);
100
1
    return was;
101
1
}
102
103
int
104
nclogopen(FILE* stream)
105
1
{
106
1
    if(!nclogginginitialized) ncloginit();
107
1
    if(stream == NULL) stream = stderr;
108
1
    nclog_global.nclogstream = stream;
109
1
    return 1;
110
1
}
111
112
/*!
113
Send logging messages. This uses a variable
114
number of arguments and operates like the stdio
115
printf function.
116
117
\param[in] tag Indicate the kind of this log message.
118
\param[in] format Format specification as with printf.
119
*/
120
121
void
122
nclog(int tag, const char* fmt, ...)
123
3
{
124
3
    if(fmt != NULL) {
125
3
      va_list args;
126
3
      va_start(args, fmt);
127
3
      ncvlog(tag,fmt,args);
128
3
      va_end(args);
129
3
    }
130
3
}
131
132
void
133
ncvlog(int level, const char* fmt, va_list ap)
134
3
{
135
3
    const char* prefix;
136
137
3
    if(!nclogginginitialized) ncloginit();
138
139
3
    if(nclog_global.nclogstream == NULL) return; /* No place to send log message */
140
3
    if(level != NCLOGERR) { /* If log level is an error, then force printing */
141
3
        if(nclog_global.loglevel < level) return;
142
3
    }
143
144
0
    prefix = nctagname(level);
145
0
    fprintf(nclog_global.nclogstream,"%s: ",prefix);
146
0
    if(fmt != NULL) {
147
0
      vfprintf(nclog_global.nclogstream, fmt, ap);
148
0
    }
149
0
    fprintf(nclog_global.nclogstream, "\n" );
150
0
    fflush(nclog_global.nclogstream);
151
0
}
152
153
void
154
nclogtext(int tag, const char* text)
155
0
{
156
0
    nclogtextn(tag,text,strlen(text));
157
0
}
158
159
/*!
160
Send arbitrarily long text as a logging message.
161
Each line will be sent using nclog with the specified tag.
162
\param[in] tag Indicate the kind of this log message.
163
\param[in] text Arbitrary text to send as a logging message.
164
*/
165
166
void
167
nclogtextn(int level, const char* text, size_t count)
168
0
{
169
0
    if(nclog_global.loglevel > level || nclog_global.nclogstream == NULL)
170
0
  return;
171
0
    fwrite(text,1,count,nclog_global.nclogstream);
172
0
    fflush(nclog_global.nclogstream);
173
0
}
174
175
static const char*
176
nctagname(int tag)
177
0
{
178
0
    if(tag < NCLOGOFF || tag >= NCLOGDEBUG)
179
0
  return "unknown";
180
0
    return nctagset[tag];
181
0
}
182
183
static int
184
nctagforname(const char* tag)
185
0
{
186
0
    int level;
187
0
    const char** p = NULL;
188
0
    for(level=0,p=nctagset;*p;p++,level++) {
189
0
  if(strcasecmp(*p,tag)==0) return level;
190
0
    }
191
0
    return -1;
192
0
}
193
194
/*!
195
Send trace messages.
196
\param[in] level Indicate the level of trace
197
\param[in] format Format specification as with printf.
198
*/
199
200
int
201
nctracelevel(int level)
202
0
{
203
0
    int oldlevel;
204
0
    if(!nclogginginitialized) ncloginit();
205
0
    oldlevel = nclog_global.tracelevel;
206
0
    if(level < 0) {
207
0
      nclog_global.tracelevel = level;
208
0
    } else { /*(level >= 0)*/
209
0
        nclog_global.tracelevel = level;
210
0
  nclogopen(NULL); /* use stderr */    
211
0
    }
212
0
    return oldlevel;
213
0
}
214
215
void
216
nctrace(int level, const char* fcn, const char* fmt, ...)
217
0
{
218
0
    va_list args;
219
0
    va_start(args, fmt);
220
0
    ncvtrace(level,fcn,fmt,args);
221
0
    va_end(args);
222
0
}
223
224
void
225
nctracemore(int level, const char* fmt, ...)
226
0
{
227
0
    va_list args;
228
0
    va_start(args, fmt);
229
0
    ncvtrace(level,NULL,fmt,args);
230
0
    va_end(args);
231
0
}
232
233
void
234
ncvtrace(int level, const char* fcn, const char* fmt, va_list ap)
235
0
{
236
0
    struct Frame* frame;
237
0
    if(!nclogginginitialized) ncloginit();
238
0
    if(fcn != NULL) {
239
0
        frame = &nclog_global.frames[nclog_global.depth];
240
0
        frame->fcn = fcn;
241
0
        frame->level = level;
242
0
        frame->depth = nclog_global.depth;
243
0
    }
244
0
    if(level <= nclog_global.tracelevel) {
245
0
  if(fcn != NULL)
246
0
            fprintf(nclog_global.nclogstream,"%s: (%d): %s:","Enter",level,fcn);
247
0
        if(fmt != NULL)
248
0
            vfprintf(nclog_global.nclogstream, fmt, ap);
249
0
        fprintf(nclog_global.nclogstream, "\n" );
250
0
        fflush(nclog_global.nclogstream);
251
0
    }
252
0
    if(fcn != NULL) nclog_global.depth++;
253
0
}
254
255
int
256
ncuntrace(const char* fcn, int err, const char* fmt, ...)
257
0
{
258
0
    va_list args;
259
0
    struct Frame* frame;
260
0
    va_start(args, fmt);
261
0
    if(nclog_global.depth == 0) {
262
0
  fprintf(nclog_global.nclogstream,"*** Unmatched untrace: %s: depth==0\n",fcn);
263
0
  goto done;
264
0
    }
265
0
    nclog_global.depth--;
266
0
    frame = &nclog_global.frames[nclog_global.depth];
267
0
    if(frame->depth != nclog_global.depth || strcmp(frame->fcn,fcn) != 0) {
268
0
  fprintf(nclog_global.nclogstream,"*** Unmatched untrace: fcn=%s expected=%s\n",frame->fcn,fcn);
269
0
  goto done;
270
0
    }
271
0
    if(frame->level <= nclog_global.tracelevel) {
272
0
        fprintf(nclog_global.nclogstream,"%s: (%d): %s: ","Exit",frame->level,frame->fcn);
273
0
  if(err)
274
0
      fprintf(nclog_global.nclogstream,"err=(%d) '%s':",err,nc_strerror(err));
275
0
        if(fmt != NULL)
276
0
            vfprintf(nclog_global.nclogstream, fmt, args);
277
0
        fprintf(nclog_global.nclogstream, "\n" );
278
0
        fflush(nclog_global.nclogstream);
279
0
    }
280
0
done:
281
0
    va_end(args);
282
0
    if(err != 0)
283
0
        return ncbreakpoint(err);
284
0
    else
285
0
  return err;
286
0
}
287
288
int
289
ncthrow(int err,const char* file,int line)
290
0
{
291
0
    if(err == 0) return err;
292
0
    return ncbreakpoint(err);
293
0
}
294
295
int
296
ncbreakpoint(int err)
297
0
{
298
0
    return err;
299
0
}
300
301
/**@}*/