OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
streamf.c
Go to the documentation of this file.
1 #include "olog.h"
2 #include "olog/streamf.h"
3 
4 #include "phash.h"
5 
6 #include <errno.h>
7 #include <stdbool.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <time.h>
13 
14 /*
15  API notes
16 
17  %% - literal %
18  %{function_name}f - function from hash
19  %{function_name}F - function from hash (no vargs)
20  %{string_name}s - string from hash
21  %[function_index]f - function from array
22  %[function_name]F - function from array (no vargs)
23  %[string_index]s - string from array
24 
25  %s - printf arguments
26  %l - severity lowercase
27  %u - severity uppercase
28  %m - severity mixed case
29  %n - severity number
30 
31  %t - time
32  time string to pass to strftime passed separately
33 
34  */
35 
36 const char *severity_l[] = { "debug", "info", "notice", "warning", "error", "critical", "alert", "emergency" };
37 const char *severity_u[] = { "DEBUG", "INFO", "NOTICE", "WARNING", "ERROR", "CRITICAL", "ALERT", "EMERGENCY" };
38 const char *severity_m[] = { "Debug", "Info", "Notice", "Warning", "Error", "Critical", "Alert", "Emergency" };
39 
40 static int olog_backend_streamf_printf(olog *olog, olog_backend *backend, uint8_t severity, va_list args) {
41 
42 // STREAMF_TYPE_STRING = 0,
43 // STREAMF_TYPE_FUNCTION = 1,
44 // STREAMF_TYPE_FUNCTION_NO_VARGS = 2,
45 // STREAMF_TYPE_FUNCTION_NO_ARGS = 3,
46 //
47 // STREAMF_TYPE_LOOKUP_HASH = 16,
48 // STREAMF_TYPE_LOOKUP_ARRAY = 32
49 
50 // const char* format = va_arg(args, const char*);
51 // int ret = vfprintf((FILE*)((olog_streamf*)backend->data)->stream, format, args);
52 
53  olog_streamf *backend_data = (olog_streamf*) backend->data;
54  int ret = 0;
55  for (unsigned i = 0; i < backend_data->command_count && !ret; i++) {
56  streamf_type type = backend_data->commands[i].type;
57  void *data = backend_data->commands[i].data;
58 
61  data = phash_get(backend_data->named_pointers, data);
62  } else if (type & STREAMF_TYPE_LOOKUP_ARRAY) {
64  data = backend_data->indexed_pointers[(unsigned long long) data];
65  }
66 
67  switch (type) {
69  ret = (fprintf((FILE*) backend_data->stream, "%s", (char*) data) < 0 ? OLOG_EXPLODED : 0);
70  break;
72  ret = (((olog_print_callback) data)(olog, backend, severity, args) < 0 ? OLOG_EXPLODED : 0);
73  break;
75  ret = (((olog_print_callback_no_vargs) data)(olog, backend, severity) < 0 ? OLOG_EXPLODED : 0);
76  break;
78  ret = (((olog_print_callback_no_args) data)(olog, backend) < 0 ? OLOG_EXPLODED : 0);
79  break;
80  default:
81  ret = OLOG_EXPLODED;
82  }
83  }
84 
85  return ret < 0 ? OLOG_EXPLODED : 0;
86 }
87 static int olog_backend_streamf_destroy(olog *olog, olog_backend *backend) {
88  olog_streamf *data = (olog_streamf*) backend->data;
89  if (data->filename && data->stream) {
90  fclose(data->stream);
91  }
92  if (data->commands) {
93  free(data->commands);
94  }
95  if (data->format) {
96  free(data->format);
97  }
98  if (data->strftime_format) {
99  free(data->strftime_format);
100  }
101  free(data);
102  return 0;
103 }
104 static int olog_backend_streamf_func_printf(olog *olog, olog_backend *backend, uint8_t severity, va_list args) {
105  const char* format = va_arg(args, const char*);
106  int ret = vfprintf((FILE*) ((olog_streamf*) backend->data)->stream, format, args);
107  return ret < 0 ? OLOG_EXPLODED : 0;
108 }
109 static int olog_backend_streamf_func_sev_lower(olog *olog, olog_backend *backend, uint8_t severity) {
110  int ret = fprintf((FILE*) ((olog_streamf*) backend->data)->stream, "%s", severity_l[severity]);
111  return ret == EOF ? OLOG_EXPLODED : 0;
112 }
113 static int olog_backend_streamf_func_sev_upper(olog *olog, olog_backend *backend, uint8_t severity) {
114  int ret = fprintf((FILE*) ((olog_streamf*) backend->data)->stream, "%s", severity_u[severity]);
115  return ret == EOF ? OLOG_EXPLODED : 0;
116 }
117 static int olog_backend_streamf_func_sev_mixed(olog *olog, olog_backend *backend, uint8_t severity) {
118  int ret = fprintf((FILE*) ((olog_streamf*) backend->data)->stream, "%s", severity_m[severity]);
119  return ret == EOF ? OLOG_EXPLODED : 0;
120 }
121 static int olog_backend_streamf_func_sev_numeric(olog *olog, olog_backend *backend, uint8_t severity) {
122  int ret = fprintf((FILE*) ((olog_streamf*) backend->data)->stream, "%u", severity);
123  return ret == EOF ? OLOG_EXPLODED : 0;
124 }
125 
126 static int olog_backend_streamf_func_time(olog *olog, olog_backend *backend) {
127  olog_streamf *data = (olog_streamf*) backend->data;
128 
129  time_t t_now = time(0);
130  struct tm *tm_now = localtime(&t_now);
131  char tstring[data->strftime_size];
132  strftime(tstring, data->strftime_size, data->strftime_format, tm_now);
133 
134  int ret = fprintf(data->stream, "%s", tstring);
135  return ret == EOF ? OLOG_EXPLODED : 0;
136 }
137 
138 static olog_streamf *olog_backend_streamf_parse_format(olog_streamf_arguments *arguments) {
139  olog_streamf *ret = malloc(sizeof(olog_streamf));
140  if (ret == NULL) {
141  return NULL;
142  }
143 
144  ret->strftime_format = NULL;
145  if (!arguments->strftime_size) {
146  ret->strftime_size = 64;
147  } else {
148  ret->strftime_size = arguments->strftime_size;
149  }
150 
151  size_t format_length = strlen(arguments->format);
152  if (format_length == 0) {
153  fprintf(stderr, "Format unspecified, invalid configuration");
154  return NULL;
155  }
156  ++format_length;
157  ret->format = malloc(sizeof(char) * format_length);
158  if (ret->format == NULL) {
159  return NULL;
160  }
161  strncpy(ret->format, arguments->format, format_length);
162 
163  char *pt = ret->format;
164  unsigned max_command_count = 1;
165 
166  while (*pt != '\0') {
167  if (*pt == '%') {
168  ++pt;
169  if (*pt == '\0') {
170  fprintf(stderr, "failed to compile log format: unfinished escape sequence at end of string");
171  return NULL;
172  } else if (*pt != '%' && *pt != 's') {
173  ++max_command_count;
174  }
175  }
176  ++pt;
177  }
178 
179  print_command *commands = malloc(sizeof(print_command) * max_command_count * 2);
180  if (commands == NULL) {
181  return NULL;
182  }
183  unsigned command_i = 0;
184 
185  bool added_user_message = false;
186  bool last_char_was_command = true;
187 
188  char *first_char;
189  first_char = pt = ret->format;
190  while (*pt != '\0') {
191 // printf("%s\n", pt);
192  if (*pt == '%') {
193  if (!last_char_was_command) {
194  commands[command_i].type = STREAMF_TYPE_STRING;
195  commands[command_i++].data = first_char;
196 
197  last_char_was_command = true;
198 
199  if (*(pt + 1) == '%') {
200  *(pt + 1) = '\0';
201  pt += 2;
202  continue;
203  } else {
204  *pt = '\0';
205  }
206  }
207 
208  ++pt;
209 
210  if (*pt == '\0') {
211  fprintf(stderr, "failed to compile log format: unfinished escape sequence at end of string");
212  return NULL;
213 // } else if (*pt == '%') {
214 // /* skip */
215  } else if (*pt == '{' || *pt == '[') {
216  char start_char = *pt;
217  char *quote_end = NULL;
218  if (start_char == '{') {
219  quote_end = strchr(++pt, '}');
220  } else {
221  quote_end = strchr(++pt, ']');
222  }
223  if (quote_end == NULL) {
224  fprintf(stderr, "failed to compile log format: unterminated named pointer name starting at: \"%16s\"", pt);
225  return NULL;
226  }
227  *quote_end = '\0';
228  quote_end++;
229  switch (*quote_end) {
230  case 's':
231  commands[command_i].type = STREAMF_TYPE_STRING;
232  break;
233  case 'f':
234  commands[command_i].type = STREAMF_TYPE_FUNCTION;
235  break;
236  case 'F':
237  commands[command_i].type = STREAMF_TYPE_FUNCTION_NO_VARGS;
238  break;
239  case 'A':
240  commands[command_i].type = STREAMF_TYPE_FUNCTION_NO_ARGS;
241  break;
242  default:
243  fprintf(stderr, "failed to compile log format: named pointer name is not followed by either `f` or `s``");
244  return NULL;
245  }
246  if (start_char == '{') {
247  if (arguments->persistent_hash) {
248  commands[command_i].type |= STREAMF_TYPE_LOOKUP_HASH;
249  commands[command_i++].data = pt;
250  } else {
251  commands[command_i++].data = phash_get(arguments->named_pointers, pt);
252  }
253  } else {
254  char *endptr;
255  errno = 0;
256  unsigned long long index = strtoull(pt, &endptr, 10);
257  if (!errno && *endptr != '\0') {
258  errno = 1;
259  }
260  if (errno) {
261  fprintf(stderr, "not a number");
262  return NULL;
263  } else {
264  if (arguments->persistent_indexes) {
265  commands[command_i].type |= STREAMF_TYPE_LOOKUP_ARRAY;
266  commands[command_i++].data = (void*) index;
267  } else {
268  commands[command_i++].data = arguments->indexed_pointers[index];
269  }
270  }
271  }
272  pt = quote_end + 1;
273  } else {
274  switch (*pt++) {
275  case 's': {
276  added_user_message = true;
277  commands[command_i].type = STREAMF_TYPE_FUNCTION;
278  commands[command_i++].data = olog_backend_streamf_func_printf;
279  }
280  break;
281  case 'l':
282  commands[command_i].type = STREAMF_TYPE_FUNCTION_NO_VARGS;
283  commands[command_i++].data = olog_backend_streamf_func_sev_lower;
284  break;
285  case 'u':
286  commands[command_i].type = STREAMF_TYPE_FUNCTION_NO_VARGS;
287  commands[command_i++].data = olog_backend_streamf_func_sev_upper;
288  break;
289  case 'm':
290  commands[command_i].type = STREAMF_TYPE_FUNCTION_NO_VARGS;
291  commands[command_i++].data = olog_backend_streamf_func_sev_mixed;
292  break;
293  case 'n':
294  commands[command_i].type = STREAMF_TYPE_FUNCTION_NO_VARGS;
295  commands[command_i++].data = olog_backend_streamf_func_sev_numeric;
296  break;
297  case 't':
298  if (ret->strftime_format == NULL) {
299  if (arguments->strftime_format == NULL) {
300  arguments->strftime_format = "%FT%T%z"; //2017-01-28T22:44:31+00:00
301  }
302  size_t strftime_format_length = strlen(arguments->strftime_format);
303  ret->strftime_format = malloc(sizeof(char) * strftime_format_length + 1);
304  if (ret->strftime_format == NULL) {
305  return NULL;
306  }
307  strncpy(ret->strftime_format, arguments->strftime_format, strftime_format_length);
308  ret->strftime_format[strftime_format_length] = '\0';
309  }
310  commands[command_i].type = STREAMF_TYPE_FUNCTION_NO_ARGS;
311  commands[command_i++].data = olog_backend_streamf_func_time;
312  break;
313  default:
314  fprintf(stderr, "failed to compile log format: unknown escape sequence: %%%c", pt[-1]);
315  return NULL;
316  }
317  continue;
318  }
319  } else if (last_char_was_command) {
320  first_char = pt++;
321  last_char_was_command = false;
322  } else {
323  ++pt;
324  }
325  }
326  if (!last_char_was_command) {
327  commands[command_i].type = STREAMF_TYPE_STRING;
328  commands[command_i++].data = first_char;
329  }
330  if (!added_user_message) {
331  commands[command_i].type = STREAMF_TYPE_FUNCTION;
332  commands[command_i++].data = olog_backend_streamf_func_printf;
333  }
334  ret->commands = commands;
335  ret->command_count = command_i;
336 
337  if (arguments->named_pointers && arguments->persistent_hash) {
338  ret->named_pointers = arguments->named_pointers;
339  }
340  if (arguments->indexed_pointers && arguments->persistent_indexes) {
341  ret->indexed_pointers = arguments->indexed_pointers;
342  }
343 
344  if (arguments->filename) {
345  ret->filename = arguments->filename;
346  ret->stream = fopen(arguments->filename, arguments->file_mode);
347  if (ret->stream == NULL) {
348  fprintf(stderr, "Error opening file %s: %s\n", arguments->filename, strerror(errno));
349  return NULL;
350  }
351  } else if (arguments->stream) {
352  ret->filename = NULL;
353  ret->stream = arguments->stream;
354  } else {
355  fprintf(stderr, "No stream or filename given\n");
356  return NULL;
357  }
358 
359  return ret;
360 }
361 
362 olog_backend olog_backend_streamf(olog_streamf_arguments *arguments, int8_t min_log_level, int8_t max_log_level) {
363  olog_backend ret = {
364  .min_log_level = min_log_level,
365  .max_log_level = max_log_level,
366  .data = (void*) olog_backend_streamf_parse_format(arguments),
367  .print_callback = olog_backend_streamf_printf,
368  .destroy_callback = olog_backend_streamf_destroy
369  };
370  return ret;
371 }
372 
an array had not been initialized Several spelling and grammar corrections were which is read from the appropriate MCF the above metadata values were hard coded A problem calculating the average background DN for SWIR bands when the moon is in the space view port was corrected The new algorithm used to calculate the average background DN for all reflective bands when the moon is in the space view port is now the same as the algorithm employed by the thermal bands For non SWIR changes in the averages are typically less than Also for non SWIR the black body DNs remain a backup in case the SV DNs are not available For SWIR the changes in computed averages were larger because the old which used the black body suffered from contamination by the micron leak As a consequence of the if SV DNs are not available for the SWIR the EV pixels will not be the granule time is used to identify the appropriate tables within the set given for one LUT the first two or last two tables respectively will be used for the interpolation If there is only one LUT in the set of it will be treated as a constant LUT The manner in which Earth View data is checked for saturation was changed Previously the raw Earth View DNs and Space View DNs were checked against the lookup table values contained in the table dn_sat The change made is to check the raw Earth and Space View DNs to be sure they are less than the maximum saturation value and to check the Space View subtracted Earth View dns against a set of values contained in the new lookup table dn_sat_ev The metadata configuration and ASSOCIATEDINSTRUMENTSHORTNAME from the MOD02HKM product The same metatdata with extensions and were removed from the MOD021KM and MOD02OBC products ASSOCIATEDSENSORSHORTNAME was set to MODIS in all products These changes are reflected in new File Specification which users may consult for exact the pow functions were eliminated in Emissive_Cal and Emissive bands replaced by more efficient code Other calculations throughout the code were also made more efficient Aside from a few round off there was no difference to the product The CPU time decreased by about for a day case and for a night case A minor bug in calculating the uncertainty index for emissive bands was corrected The frame index(0-based) was previously being used the frame number(1-based) should have been used. There were only a few minor changes to the uncertainty index(maximum of 1 digit). 3. Some inefficient arrays(Sigma_RVS_norm_sq) were eliminated and some code lines in Preprocess_L1A_Data were moved into Process_OBCEng_Emiss. There were no changes to the product. Required RAM was reduced by 20 MB. Now
#define NULL
Definition: decode_rs.h:63
@ STREAMF_TYPE_FUNCTION
Definition: streamf.h:29
int(* olog_print_callback_no_args)(olog *olog, olog_backend *backend)
Definition: streamf.h:25
float tm[MODELMAX]
A simple logger, capable of dispatching log events to multiple end points.
A simple dictionary library for storing pointers.
character(len=1000) if
Definition: names.f90:13
int(* olog_print_callback)(olog *olog, olog_backend *backend, uint8_t severity, va_list args)
Definition: streamf.h:23
size_t strftime_size
Definition: streamf.h:47
olog_backend olog_backend_streamf(olog_streamf_arguments *arguments, int8_t min_log_level, int8_t max_log_level)
Definition: streamf.c:362
char * format
Definition: streamf.h:46
streamf_type type
Definition: streamf.h:38
char * filename
Definition: streamf.h:44
int errno
Definition: olog.c:11
@ STREAMF_TYPE_STRING
Definition: streamf.h:28
FILE * stream
Definition: streamf.h:45
unsigned command_count
Definition: streamf.h:51
enum streamf_type_t streamf_type
Definition: streamf.h:36
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude data
Definition: HISTORY.txt:356
const char * severity_m[]
Definition: streamf.c:38
void * phash_get(phash *h, const char *key)
Find a pointer associated with the given string.
Definition: phash.c:205
void * data
Storage for backend use.
Definition: olog.h:84
#define OLOG_EXPLODED
Definition: olog.h:53
@ STREAMF_TYPE_LOOKUP_HASH
Definition: streamf.h:33
int(* olog_print_callback_no_vargs)(olog *olog, olog_backend *backend, uint8_t severity)
Definition: streamf.h:24
print_command * commands
Definition: streamf.h:50
char * strftime_format
Definition: streamf.h:46
@ STREAMF_TYPE_LOOKUP_ARRAY
Definition: streamf.h:34
format
Definition: mapgen.py:185
const char * severity_u[]
Definition: streamf.c:37
this program makes no use of any feature of the SDP Toolkit that could generate such a then geolocation is calculated at that and then aggregated up to Resolved feature request Bug by adding three new int8 SDSs for each high resolution offsets between the high resolution geolocation and a bi linear interpolation extrapolation of the positions This can be used to reconstruct the high resolution geolocation Resolved Bug by delaying cumulation of gflags until after validation of derived products Resolved Bug by setting Latitude and Longitude to the correct fill resolving to support Near Real Time because they may be unnecessary if use of entrained ephemeris and attitude data is turned resolving bug report Corrected to filter out Aqua attitude records with missing status helping resolve bug MOD_PR03 will still correctly write scan and pixel data that does not depend upon the start time
Definition: HISTORY.txt:248
void * data
Definition: streamf.h:39
PARAM_TYPE_NONE Default value No parameter is buried in the product name name_prefix is case insensitive string compared to the product name PARAM_TYPE_VIS_WAVE The visible wavelength bands from the sensor are buried in the product name The product name is compared by appending and name_suffix ie aph_412_giop where prod_ix will be set to PARAM_TYPE_IR_WAVE same search method as PARAM_TYPE_VIS_WAVE except only wavelength above are looped through but prod_ix is still based ie aph_2_giop for the second and prod_ix set to PARAM_TYPE_INT name_prefix is compared with the beginning of the product name If name_suffix is not empty the it must match the end of the product name The characters right after the prefix are read as an integer and prod_ix is set to that number strncpy(l2prod->name_prefix, "myprod", UNITLEN)
for(i=0;i< NROOTS;i++) s[i]
Definition: decode_rs.h:85
int i
Definition: decode_rs.h:71
phash * named_pointers
Definition: streamf.h:48
const char * severity_l[]
Definition: streamf.c:36
@ STREAMF_TYPE_FUNCTION_NO_VARGS
Definition: streamf.h:30
void ** indexed_pointers
Definition: streamf.h:49
@ STREAMF_TYPE_FUNCTION_NO_ARGS
Definition: streamf.h:31