Coverage Report

Created: 2025-10-28 07:06

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.loglevel < level || nclog_global.nclogstream == NULL) {
140
3
        return;
141
3
    }
142
143
0
    prefix = nctagname(level);
144
0
    fprintf(nclog_global.nclogstream,"%s: ",prefix);
145
0
    if(fmt != NULL) {
146
0
      vfprintf(nclog_global.nclogstream, fmt, ap);
147
0
    }
148
0
    fprintf(nclog_global.nclogstream, "\n" );
149
0
    fflush(nclog_global.nclogstream);
150
0
}
151
152
void
153
nclogtext(int tag, const char* text)
154
0
{
155
0
    nclogtextn(tag,text,strlen(text));
156
0
}
157
158
/*!
159
Send arbitrarily long text as a logging message.
160
Each line will be sent using nclog with the specified tag.
161
\param[in] tag Indicate the kind of this log message.
162
\param[in] text Arbitrary text to send as a logging message.
163
*/
164
165
void
166
nclogtextn(int level, const char* text, size_t count)
167
0
{
168
0
    if(nclog_global.loglevel > level || nclog_global.nclogstream == NULL)
169
0
  return;
170
0
    fwrite(text,1,count,nclog_global.nclogstream);
171
0
    fflush(nclog_global.nclogstream);
172
0
}
173
174
static const char*
175
nctagname(int tag)
176
0
{
177
0
    if(tag < NCLOGOFF || tag >= NCLOGDEBUG)
178
0
  return "unknown";
179
0
    return nctagset[tag];
180
0
}
181
182
static int
183
nctagforname(const char* tag)
184
0
{
185
0
    int level;
186
0
    const char** p = NULL;
187
0
    for(level=0,p=nctagset;*p;p++,level++) {
188
0
  if(strcasecmp(*p,tag)==0) return level;
189
0
    }
190
0
    return -1;
191
0
}
192
193
/*!
194
Send trace messages.
195
\param[in] level Indicate the level of trace
196
\param[in] format Format specification as with printf.
197
*/
198
199
int
200
nctracelevel(int level)
201
0
{
202
0
    int oldlevel;
203
0
    if(!nclogginginitialized) ncloginit();
204
0
    oldlevel = nclog_global.tracelevel;
205
0
    if(level < 0) {
206
0
      nclog_global.tracelevel = level;
207
0
    } else { /*(level >= 0)*/
208
0
        nclog_global.tracelevel = level;
209
0
  nclogopen(NULL); /* use stderr */    
210
0
    }
211
0
    return oldlevel;
212
0
}
213
214
void
215
nctrace(int level, const char* fcn, const char* fmt, ...)
216
0
{
217
0
    va_list args;
218
0
    va_start(args, fmt);
219
0
    ncvtrace(level,fcn,fmt,args);
220
0
    va_end(args);
221
0
}
222
223
void
224
nctracemore(int level, const char* fmt, ...)
225
0
{
226
0
    va_list args;
227
0
    va_start(args, fmt);
228
0
    ncvtrace(level,NULL,fmt,args);
229
0
    va_end(args);
230
0
}
231
232
void
233
ncvtrace(int level, const char* fcn, const char* fmt, va_list ap)
234
0
{
235
0
    struct Frame* frame;
236
0
    if(!nclogginginitialized) ncloginit();
237
0
    if(fcn != NULL) {
238
0
        frame = &nclog_global.frames[nclog_global.depth];
239
0
        frame->fcn = fcn;
240
0
        frame->level = level;
241
0
        frame->depth = nclog_global.depth;
242
0
    }
243
0
    if(level <= nclog_global.tracelevel) {
244
0
  if(fcn != NULL)
245
0
            fprintf(nclog_global.nclogstream,"%s: (%d): %s:","Enter",level,fcn);
246
0
        if(fmt != NULL)
247
0
            vfprintf(nclog_global.nclogstream, fmt, ap);
248
0
        fprintf(nclog_global.nclogstream, "\n" );
249
0
        fflush(nclog_global.nclogstream);
250
0
    }
251
0
    if(fcn != NULL) nclog_global.depth++;
252
0
}
253
254
int
255
ncuntrace(const char* fcn, int err, const char* fmt, ...)
256
0
{
257
0
    va_list args;
258
0
    struct Frame* frame;
259
0
    va_start(args, fmt);
260
0
    if(nclog_global.depth == 0) {
261
0
  fprintf(nclog_global.nclogstream,"*** Unmatched untrace: %s: depth==0\n",fcn);
262
0
  goto done;
263
0
    }
264
0
    nclog_global.depth--;
265
0
    frame = &nclog_global.frames[nclog_global.depth];
266
0
    if(frame->depth != nclog_global.depth || strcmp(frame->fcn,fcn) != 0) {
267
0
  fprintf(nclog_global.nclogstream,"*** Unmatched untrace: fcn=%s expected=%s\n",frame->fcn,fcn);
268
0
  goto done;
269
0
    }
270
0
    if(frame->level <= nclog_global.tracelevel) {
271
0
        fprintf(nclog_global.nclogstream,"%s: (%d): %s: ","Exit",frame->level,frame->fcn);
272
0
  if(err)
273
0
      fprintf(nclog_global.nclogstream,"err=(%d) '%s':",err,nc_strerror(err));
274
0
        if(fmt != NULL)
275
0
            vfprintf(nclog_global.nclogstream, fmt, args);
276
0
        fprintf(nclog_global.nclogstream, "\n" );
277
0
        fflush(nclog_global.nclogstream);
278
0
    }
279
0
done:
280
0
    va_end(args);
281
0
    if(err != 0)
282
0
        return ncbreakpoint(err);
283
0
    else
284
0
  return err;
285
0
}
286
287
int
288
ncthrow(int err,const char* file,int line)
289
0
{
290
0
    if(err == 0) return err;
291
0
    return ncbreakpoint(err);
292
0
}
293
294
int
295
ncbreakpoint(int err)
296
0
{
297
0
    return err;
298
0
}
299
300
/**@}*/