bes  Updated for version 3.20.10
FONcAttributes.cc
1 // FONcAttributes.cc
2 
3 // This file is part of BES Netcdf File Out Module
4 
5 // Copyright (c) 2004,2005 University Corporation for Atmospheric Research
6 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 //
22 // You can contact University Corporation for Atmospheric Research at
23 // 3080 Center Green Drive, Boulder, CO 80301
24 
25 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
26 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
27 //
28 // Authors:
29 // pwest Patrick West <pwest@ucar.edu>
30 // jgarcia Jose Garcia <jgarcia@ucar.edu>
31 
32 #include <sstream>
33 
34 using std::istringstream;
35 
36 #include <netcdf.h>
37 
38 #include <BESDebug.h>
39 #include <BESInternalError.h>
40 #include <BESUtil.h>
41 #include <cstdlib>
42 
43 #include "DapFunctionUtils.h"
44 
45 #include "FONcAttributes.h"
46 #include "FONcUtils.h"
47 
79 void FONcAttributes::add_variable_attributes(int ncid, int varid, BaseType *b, bool is_nc_enhanced,bool is_dap4) {
80  string emb_name;
81  BaseType *parent = b->get_parent();
82  if (parent) {
83  //BESDEBUG("dap", "FONcAttributes::parent name is "<< parent->name() <<endl);
84  //BESDEBUG("dap", "FONcAttributes::parent type is "<< parent->type() <<endl);
85  if(true != is_dap4 || parent->type()!=dods_group_c)
86  FONcAttributes::add_variable_attributes_worker(ncid, varid, parent, emb_name, is_nc_enhanced,is_dap4);
87  }
88  // addattrs_workerA(ncid, varid, b, "");
89  // Add DAP4 attribute support by using attributes().
90 
91  BESDEBUG("dap", "FONcAttributes::add_variable_attributes() after parent "<<endl);
92  if(is_dap4)
93  add_dap4_attributes(ncid, varid, b->attributes(), b->name(), "", is_nc_enhanced);
94  else
95  add_attributes(ncid, varid, b->get_attr_table(), b->name(), "", is_nc_enhanced);
96 
97 }
98 
113 void FONcAttributes::add_variable_attributes_worker(int ncid, int varid, BaseType *b, string &emb_name,
114  bool is_nc_enhanced,bool is_dap4) {
115 
116  BaseType *parent = b->get_parent();
117  if (parent) {
118  FONcAttributes::add_variable_attributes_worker(ncid, varid, parent, emb_name, is_nc_enhanced,is_dap4);
119  }
120  if (!emb_name.empty()) {
121  emb_name += FONC_EMBEDDED_SEPARATOR;
122  }
123  emb_name += b->name();
124  // addattrs_workerA(ncid, varid, b, emb_name);
125  if(is_dap4)
126  add_dap4_attributes(ncid, varid, b->attributes(), b->name(), emb_name, is_nc_enhanced);
127  else
128  add_attributes(ncid, varid, b->get_attr_table(), b->name(), emb_name, is_nc_enhanced);
129 }
130 
131 
146 void FONcAttributes::add_attributes(int ncid, int varid, AttrTable &attrs, const string &var_name,
147  const string &prepend_attr, bool is_nc_enhanced) {
148 
149  unsigned int num_attrs = attrs.get_size();
150  if (num_attrs) {
151  AttrTable::Attr_iter i = attrs.attr_begin();
152  AttrTable::Attr_iter e = attrs.attr_end();
153  for (; i != e; i++) {
154  unsigned int num_vals = attrs.get_attr_num(i);
155  if (num_vals) {
156  add_attributes_worker(ncid, varid, var_name, attrs, i, prepend_attr, is_nc_enhanced);
157  }
158  }
159  }
160 }
161 
176 //void FONcAttributes::add_dap4_attributes(int ncid, int varid, AttrTable &attrs, const string &var_name,
177 void FONcAttributes::add_dap4_attributes(int ncid, int varid, D4Attributes *d4_attrs, const string &var_name,
178  const string &prepend_attr, bool is_nc_enhanced) {
179 
180  BESDEBUG("dap", "FONcAttributes::add_dap4_attributes() number of attributes "<< d4_attrs <<endl);
181  for (D4Attributes::D4AttributesIter ii = d4_attrs->attribute_begin(), ee = d4_attrs->attribute_end(); ii != ee; ++ii) {
182  string name = (*ii)->name();
183  //BESDEBUG("dap", "FONcAttributes:: attribute name is "<<name <<endl);
184  unsigned int num_vals = (*ii)->num_values();
185  //BESDEBUG("dap", "FONcAttributes:: num_vals is "<<num_vals <<endl);
186  // d4_attrs includes all the global containers' attributes, which is not right.
187  if (num_vals || varid == NC_GLOBAL)
188  add_dap4_attributes_worker(ncid, varid, var_name, *ii, prepend_attr, is_nc_enhanced);
189  }
190 }
191 
205 void FONcAttributes::add_attributes_worker(int ncid, int varid, const string &var_name,
206  AttrTable &attrs, AttrTable::Attr_iter &attr,
207  const string &prepend_attr, bool is_nc_enhanced) {
208 
209  AttrType attrType = attrs.get_attr_type(attr);
210 
211  string attr_name = attrs.get_name(attr);
212  string new_attr_name("");
213  if (!prepend_attr.empty()) {
214  new_attr_name = prepend_attr + FONC_EMBEDDED_SEPARATOR + attr_name;
215  } else {
216 
217  // If we're doing global attributes AND it's an attr table, and its name is "special"
218  // (ends with "_GLOBAL"), then we suppress the use of the attrTable name in
219  // the NetCDF Attributes name.
220  if (varid == NC_GLOBAL && attrType == Attr_container && BESUtil::endsWith(attr_name, "_GLOBAL")) {
221  BESDEBUG("fonc",
222  "Suppressing global AttributeTable name '" << attr_name
223  << "' from inclusion in NetCDF attributes namespace chain."
224  << endl);
225  new_attr_name = "";
226  } else {
227  new_attr_name = attr_name;
228  }
229  }
230 
231 //Note: Leave the following #if 0 #endif block for the time being. Don't change to NBEBUG.
232 #if 0
233  // This was the old way of doing it and it polluted the attribute names
234  // by prepending full qualified variable names to the attribute name..
235  string new_name = new_attr_name;
236  if (!var_name.empty()) {
237  new_name = var_name + FONC_ATTRIBUTE_SEPARATOR + new_attr_name;
238  }
239 
240  // BESDEBUG("fonc","new_name: " << new_name << " new_attr_name: " << new_attr_name << " var_name: " << var_name << endl);
241 
242  new_name = FONcUtils::id2netcdf(new_name);
243 #endif
244 
245  string new_name = FONcUtils::id2netcdf(new_attr_name);;
246  BESDEBUG("fonc", "FONcAttributes name: " << new_name << endl);
247  BESDEBUG("fonc", "FONcAttributes type: " << attrType << endl);
248 
249 
250  if (varid == NC_GLOBAL) {
251  BESDEBUG("fonc", "FONcAttributes::add_attrbutes_worker() - Adding global attributes " << attr_name << endl);
252  } else {
253  BESDEBUG("fonc", "FONcAttributes::add_attributes_worker() - Adding attribute " << new_name << endl);
254  }
255 
256  // If we want to map the attributes of the datatypes to those of netCDF-4, KY 2020-02-14
257  if (is_nc_enhanced == true)
258  write_attrs_for_nc4_types(ncid, varid, var_name, new_attr_name, new_name, attrs, attr, is_nc_enhanced);
259  else {
260  int stax = NC_NOERR;
261  unsigned int attri = 0;
262  unsigned int num_vals = attrs.get_attr_num(attr);
263  switch (attrType) {
264  case Attr_container: {
265  // flatten
266  BESDEBUG("fonc",
267  "Attribute " << attr_name << " is an attribute container. new_attr_name: \"" << new_attr_name
268  << "\"" << endl);
269  AttrTable *container = attrs.get_attr_table(attr);
270  if (container) {
271  add_attributes(ncid, varid, *container, var_name, new_attr_name, is_nc_enhanced);
272  }
273  }
274  break;
275  case Attr_byte: {
276  // unsigned char
277  // This should be converted to short to be consistent with the array.
278  // The classic model doesn't support unsigned char.
279  vector<short>vals;
280  vals.resize(num_vals);
281  for (attri = 0; attri < num_vals; attri++) {
282  string val = attrs.get_attr(attr, attri);
283  istringstream is(val);
284  unsigned int uival = 0;
285  is >> uival;
286  vals[attri] = (short) uival;
287  }
288  stax = nc_put_att_short(ncid, varid, new_name.c_str(), NC_SHORT,
289  num_vals, &vals[0]);
290  if (stax != NC_NOERR) {
291  string err = (string) "File out netcdf, "
292  + "failed to write byte attribute " + new_name;
293  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
294  }
295  }
296  break;
297  case Attr_int16: {
298  // short
299  vector<short>vals;
300  vals.resize(num_vals);
301  for (attri = 0; attri < num_vals; attri++) {
302  string val = attrs.get_attr(attr, attri);
303  istringstream is(val);
304  short sval = 0;
305  is >> sval;
306  vals[attri] = sval;
307  }
308  stax = nc_put_att_short(ncid, varid, new_name.c_str(), NC_SHORT,
309  num_vals, &vals[0]);
310  if (stax != NC_NOERR) {
311  string err = (string) "File out netcdf, "
312  + "failed to write short attribute " + new_name;
313  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
314  }
315  }
316  break;
317  case Attr_uint16: {
318  // unsigned short
319  // (needs to be big enough to store an unsigned short
320  vector<int>vals;
321  vals.resize(num_vals);
322  for (attri = 0; attri < num_vals; attri++) {
323  string val = attrs.get_attr(attr, attri);
324  istringstream is(val);
325  int ival = 0;
326  is >> ival;
327  vals[attri] = ival;
328  }
329  stax = nc_put_att_int(ncid, varid, new_name.c_str(), NC_INT, num_vals,
330  &vals[0]);
331  if (stax != NC_NOERR) {
332  string err = (string) "File out netcdf, "
333  + "failed to write unsinged short attribute " + new_name;
334  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
335  }
336  }
337  break;
338  case Attr_int32: {
339  // int
340  vector<int> vals;
341  vals.resize(num_vals);
342  for (attri = 0; attri < num_vals; attri++) {
343  string val = attrs.get_attr(attr, attri);
344  istringstream is(val);
345  int ival = 0;
346  is >> ival;
347  vals[attri] = ival;
348  }
349  stax = nc_put_att_int(ncid, varid, new_name.c_str(), NC_INT, num_vals,
350  &vals[0]);
351  if (stax != NC_NOERR) {
352  string err = (string) "File out netcdf, "
353  + "failed to write int attribute " + new_name;
354  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
355  }
356  }
357  break;
358  case Attr_uint32: {
359  // uint
360  // needs to be big enough to store an unsigned int
361  string err = (string) "File out netcdf, "
362  + "failed to write unsigned int attribute " + new_name;
363  err = err + " for classic model because of potential overflow. ";
364  err = err + " Please use the netCDF4 enhanced model. ";
365  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
366  // Note: the following #if 0 #endif is for reminder to developers only.
367  // Don't change it to NBEDBUG.
368 #if 0
369  vector<int>vals;
370  vals.resize(num_vals);
371  for (attri = 0; attri < num_vals; attri++) {
372  string val = attrs.get_attr(attr, attri);
373  istringstream is(val);
374  int lval = 0;
375  is >> lval;
376  vals[attri] = lval;
377  }
378  stax = nc_put_att_int(ncid, varid, new_name.c_str(), NC_INT, num_vals,
379  &vals[0]);
380  if (stax != NC_NOERR) {
381  string err = (string) "File out netcdf, "
382  + "failed to write unsigned int attribute " + new_name;
383  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
384  }
385 #endif
386  }
387  break;
388  case Attr_float32: {
389  // float
390  vector<float> vals;
391  vals.resize(num_vals);
392  for (attri = 0; attri < num_vals; attri++) {
393  string val = attrs.get_attr(attr, attri);
394  const char *cval = val.c_str();
395  //istringstream is(val);
396  float fval = 0;
397  fval = strtod(cval,NULL);
398  //is >> fval;
399  vals[attri] = fval;
400  }
401  stax = nc_put_att_float(ncid, varid, new_name.c_str(), NC_FLOAT,
402  num_vals, &vals[0]);
403  if (stax != NC_NOERR) {
404  string err = (string) "File out netcdf, "
405  + "failed to write float attribute " + new_name;
406  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
407  }
408  }
409  break;
410  case Attr_float64: {
411  // double
412  vector<double>vals;
413  vals.resize(num_vals);
414  for (attri = 0; attri < num_vals; attri++) {
415  string val = attrs.get_attr(attr, attri);
416  const char *cval = val.c_str();
417  //istringstream is(val);
418  double dval = 0;
419  dval = strtod(cval,NULL);
420  //is >> dval;
421  vals[attri] = dval;
422  }
423  stax = nc_put_att_double(ncid, varid, new_name.c_str(), NC_DOUBLE,
424  num_vals, &vals[0]);
425  if (stax != NC_NOERR) {
426  string err = (string) "File out netcdf, "
427  + "failed to write double attribute " + new_name;
428  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
429  }
430  }
431  break;
432  case Attr_string:
433  case Attr_url:
434  case Attr_other_xml: // Added. jhrg 12.27.2011
435  {
436  // string
437  string val = attrs.get_attr(attr, 0);
438  for (attri = 1; attri < num_vals; attri++) {
439  val += "\n" + attrs.get_attr(attr, attri);
440  }
441  if (attr_name != _FillValue) {
442  stax = nc_put_att_text(ncid, varid, new_name.c_str(), val.length(), val.c_str());
443  } else {
444  BESDEBUG("fonc",
445  "FONcAttributes::add_attributes_worker - Original attribute value is first character: "
446  << val.c_str()[0] << endl);
447  stax = nc_put_att_text(ncid, varid, new_name.c_str(), 1, val.c_str());
448  if (stax == NC_NOERR) {
449  // New name for attribute _FillValue with original value
450  string new_name_fillvalue = "Orig_FillValue";
451  BESDEBUG("fonc",
452  "FONcAttributes::add_attributes_worker - New attribute value is original value: "
453  << val.c_str() << endl);
454  // This line causes the segmentation fault since attrs is changed and the original iterator of attrs doesn't exist anymore.
455  // So it causes the segmentation fault when next attribute is fetched in the for loop of the add_attributes(). KY 2019-12-13
456 #if 0
457  attrs.append_attr(new_name_fillvalue,"String", val);
458 #endif
459  stax = nc_put_att_text(ncid, varid, new_name_fillvalue.c_str(), val.length(), val.c_str());
460  }
461  }
462 
463  if (stax != NC_NOERR) {
464  string err = (string) "File out netcdf, "
465  + "failed to write string attribute " + new_name;
466  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
467  }
468  }
469  break;
470 
471  case Attr_unknown: {
472  string err = (string) "File out netcdf, "
473  + "failed to write unknown type of attribute " + new_name;
474  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
475  }
476  break;
477  }
478  }
479 }
480 
493 void FONcAttributes::add_dap4_attributes_worker(int ncid, int varid, const string &var_name,
494  D4Attribute* attr,
495  const string &prepend_attr, bool is_nc_enhanced) {
496  D4AttributeType d4_attr_type = attr->type();
497 
498  string d4_attr_name = attr->name();
499  BESDEBUG("dap", "FONcAttributes:: D4 attribute name is "<<d4_attr_name <<endl);
500  string new_attr_name("");
501  if (!prepend_attr.empty()) {
502  new_attr_name = prepend_attr + FONC_EMBEDDED_SEPARATOR + d4_attr_name;
503  BESDEBUG("dap", "FONcAttributes:: D4 new attribute name is "<<new_attr_name <<endl);
504 
505  } else {
506 
507  // If we're doing global attributes AND it's an attr table, and its name is "special"
508  // (ends with "_GLOBAL"), then we suppress the use of the attrTable name in
509  // the NetCDF Attributes name.
510  if (varid == NC_GLOBAL && d4_attr_type == attr_container_c && (BESUtil::endsWith(d4_attr_name, "_GLOBAL") ||
511  BESUtil::endsWith(d4_attr_name, "HDF5_GLOBAL_integer_64"))) {
512  BESDEBUG("fonc",
513  "Suppressing global AttributeTable name '" << d4_attr_name
514  << "' from inclusion in NetCDF attributes namespace chain."
515  << endl);
516  new_attr_name = "";
517  } else {
518  new_attr_name = d4_attr_name;
519  }
520  }
521 
522 
523 //Note: Leave the following #if 0 #endif block for the time being. Don't change to NBEBUG.
524 #if 0
525  // This was the old way of doing it and it polluted the attribute names
526  // by prepending full qualified variable names to the attribute name..
527  string new_name = new_attr_name;
528  if (!var_name.empty()) {
529  new_name = var_name + FONC_ATTRIBUTE_SEPARATOR + new_attr_name;
530  }
531 
532  // BESDEBUG("fonc","new_name: " << new_name << " new_attr_name: " << new_attr_name << " var_name: " << var_name << endl);
533 
534  new_name = FONcUtils::id2netcdf(new_name);
535 #endif
536 
537  string new_name = FONcUtils::id2netcdf(new_attr_name);;
538 
539 #if !NDEBUG
540  if (varid == NC_GLOBAL) {
541  BESDEBUG("fonc", "FONcAttributes::addattrs() - Adding global attributes " << d4_attr_name << endl);
542  } else {
543  BESDEBUG("fonc", "FONcAttributes::addattrs() - Adding attribute " << new_name << endl);
544  }
545 #endif
546 
547  // If we want to map the attributes of the datatypes to those of netCDF-4, KY 2020-02-14
548  if (is_nc_enhanced == true)
549  //write_dap4_attrs_for_nc4_types(ncid, varid, var_name, new_attr_name, new_name, d4_attrs, attr, is_nc_enhanced);
550  write_dap4_attrs_for_nc4_types(ncid, varid, var_name, new_attr_name, new_name, attr, is_nc_enhanced);
551  else {
552  int stax = NC_NOERR;
553  string attr_type = "unknown"; // Used for error messages. jhrg 6/18/20
554  unsigned int attri = 0;
555  //unsigned int num_vals = attrs.get_attr_num(attr);
556  unsigned int num_vals = attr->num_values();
557  switch (d4_attr_type) {
558  case attr_container_c: {
559  // flatten
560  BESDEBUG("fonc",
561  "Attribute " << d4_attr_name << " is an attribute container. new_attr_name: \""
562  << new_attr_name
563  << "\"" << endl);
564  D4Attributes *c_attributes = attr->attributes();
565  if (c_attributes) {
566  add_dap4_attributes(ncid, varid, c_attributes, var_name, new_attr_name, is_nc_enhanced);
567  }
568 
569  }
570  break;
571 
572  case attr_int8_c:{
573 
574  // 8-bit integer
575  vector<int8_t> vals;
576  vals.resize(num_vals);
577  attri = 0;
578  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
579  string val = *vi;
580  istringstream is(val);
581  int uival = 0;
582  is >> uival;
583  vals[attri] = (int8_t) uival;
584  ++attri;
585  }
586  stax = nc_put_att_schar(ncid, varid, new_name.c_str(), NC_BYTE,
587  num_vals, &vals[0]);
588  if (stax != NC_NOERR) {
589  string err = (string) "File out netcdf-4 classic for DAP4, "
590  + "failed to write signed 8-bit integer attribute " + new_name;
591  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
592  }
593  }
594  break;
595 
596  case attr_byte_c:
597  case attr_uint8_c: {
598  vector<short> vals;
599  vals.resize(num_vals);
600  attri = 0;
601  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
602  string val = *vi;
603  istringstream is(val);
604  // Follow the classic code, the stringstream doesn't work well with int8,
605  // no overflow when casted back to vals.
606  unsigned int uival = 0;
607  is >> uival;
608  vals[attri] = (short) uival;
609  ++attri;
610  }
611  stax = nc_put_att_short(ncid, varid, new_name.c_str(), NC_SHORT, num_vals, &vals[0]);
612 
613  }
614  break;
615 
616  case attr_int16_c: {
617  // short
618  vector<short> vals;
619  vals.resize(num_vals);
620  attri = 0;
621  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
622  string val = *vi;
623  istringstream is(val);
624  short sval = 0;
625  is >> sval;
626  vals[attri] = sval;
627  ++attri;
628  }
629 
630  stax = nc_put_att_short(ncid, varid, new_name.c_str(), NC_SHORT, num_vals, &vals[0]);
631 
632  break;
633  }
634 
635  case attr_uint16_c: {
636  // unsigned short
637  // (needs to be big enough to store an unsigned short
638  attri = 0;
639  //int vals[num_vals];
640  vector<int> vals;
641  vals.resize(num_vals);
642  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
643  string val = *vi;
644  istringstream is(val);
645  int ival = 0;
646  is >> ival;
647  vals[attri] = ival;
648  ++attri;
649  }
650 
651  stax = nc_put_att_int(ncid, varid, new_name.c_str(), NC_INT, num_vals, &vals[0]);
652 
653  break;
654  }
655 
656  case attr_int32_c: {
657  // int
658  vector<int>vals;
659  vals.resize(num_vals);
660  attri = 0;
661  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
662  string val = *vi;
663  istringstream is(val);
664  int sval = 0;
665  is >> sval;
666  vals[attri] = sval;
667  ++attri;
668  }
669 
670  stax = nc_put_att_int(ncid, varid, new_name.c_str(), NC_INT, num_vals, &vals[0]);
671 
672  break;
673  }
674 
675  case attr_uint32_c: {
676  // uint
677  // needs to be big enough to store an unsigned int
678  vector<int>vals;
679  vals.resize(num_vals);
680  attri = 0;
681  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
682  string val = *vi;
683  istringstream is(val);
684  int sval = 0;
685  is >> sval;
686  vals[attri] = sval;
687  ++attri;
688  }
689 
690  stax = nc_put_att_int(ncid, varid, new_name.c_str(), NC_INT, num_vals, &vals[0]);
691 
692  break;
693  }
694 
695  case attr_float32_c: {
696  // float
697  vector<float>vals;
698  vals.resize(num_vals);
699  attri = 0;
700  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
701  string val = *vi;
702  const char *cval = val.c_str();
703  //istringstream is(val);
704  float sval = 0;
705  sval = strtod(cval,NULL);
706  //is >> sval;
707  vals[attri] = sval;
708  ++attri;
709  }
710 
711  stax = nc_put_att_float(ncid, varid, new_name.c_str(), NC_FLOAT, num_vals, &vals[0]);
712 
713  break;
714  }
715 
716  case attr_float64_c: {
717  // double
718  vector<double>vals;
719  vals.resize(num_vals);
720  attri = 0;
721  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
722  string val = *vi;
723  const char *cval = val.c_str();
724  //istringstream is(val);
725  double sval = 0;
726  sval = strtod(cval,NULL);
727  //is >> sval;
728  vals[attri] = sval;
729  ++attri;
730  }
731  stax = nc_put_att_double(ncid, varid, new_name.c_str(), NC_DOUBLE, num_vals, &vals[0]);
732 
733  break;
734  }
735 
736  case attr_str_c:
737  case attr_url_c:
738  case attr_otherxml_c: { // Added. jhrg 12.27.2011
739  attr_type = "string";
740  D4Attribute::D4AttributeIter vi, ve;
741  vi = attr->value_begin();
742  ve = attr->value_end();
743 
744  string val = (*vi);
745 
746  vi++;
747  for (; vi != ve; vi++) {
748  val += "\n" + *vi;
749  }
750 
751  if (d4_attr_name != _FillValue) {
752  stax = nc_put_att_text(ncid, varid, new_name.c_str(), val.length(), val.c_str());
753  }
754  else {
755  BESDEBUG("fonc",
756  "FONcAttributes::add_attributes_worker - Original attribute value is first character: "
757  << val.c_str()[0] << endl);
758  stax = nc_put_att_text(ncid, varid, new_name.c_str(), 1, val.c_str());
759  if (stax == NC_NOERR) {
760  // New name for attribute _FillValue with original value
761  string new_name_fillvalue = "Orig_FillValue";
762  BESDEBUG("fonc",
763  "FONcAttributes::add_attributes_worker - New attribute value is original value: "
764  << val.c_str() << endl);
765  // This line causes the segmentation fault since attrs is changed and the original iterator of attrs doesn't exist anymore.
766  // So it causes the segmentation fault when next attribute is fetched in the for loop of the add_attributes(). KY 2019-12-13
767 #if 0
768  attrs.append_attr(new_name_fillvalue,"String", val);
769 #endif
770  stax = nc_put_att_text(ncid, varid, new_name_fillvalue.c_str(), val.length(), val.c_str());
771  }
772  }
773 
774  break;
775  }
776 
777  case attr_null_c:
778  case attr_int64_c:
779  case attr_uint64_c:
780  case attr_enum_c:
781  case attr_opaque_c:
782  default: {
783  // Temporarily don't support these types.TODO: add the support.
784  string err = (string) "File out netcdf, failed to write unknown/unsupported type of attribute " + new_name;
785  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
786  break;
787  }
788  }
789 
790  if (stax != NC_NOERR) {
791  string err = (string) "File out netcdf, failed to write " + attr_type + " attribute " + new_name;
792  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
793  }
794  }
795 }
796 
797 
811 void FONcAttributes::add_original_name(int ncid, int varid,
812  const string &var_name, const string &orig) {
813  if (var_name != orig) {
814  string attr_name = FONC_ORIGINAL_NAME;
815  int stax = nc_put_att_text(ncid, varid, attr_name.c_str(),
816  orig.length(), orig.c_str());
817  if (stax != NC_NOERR) {
818  string err = (string) "File out netcdf, "
819  + "failed to write change of name attribute for "
820  + var_name;
821  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
822  }
823  }
824 }
838 void
839 FONcAttributes::write_attrs_for_nc4_types(int ncid, int varid, const string &var_name, const string &global_attr_name,
840  const string &var_attr_name, AttrTable attrs, AttrTable::Attr_iter &attr,
841  bool is_nc_enhanced) {
842 
843  int stax = NC_NOERR;
844  string attr_type = "unknown"; // Used for error messages. jhrg 6/18/20
845  AttrType attrType = attrs.get_attr_type(attr);
846  BESDEBUG("fonc", "FONcAttributes write_attrs_for_nc4_type name: " << var_attr_name << endl);
847  BESDEBUG("fonc", "FONcAttributes write_attrs_for_nc4_type type: " << attrType << endl);
848  unsigned int attri = 0;
849  unsigned int num_vals = attrs.get_attr_num(attr);
850  switch (attrType) {
851  case Attr_container: {
852  // flatten
853  BESDEBUG("fonc", "This is an attribute container. attr_name: \"" << global_attr_name << "\"" << endl);
854  AttrTable *container = attrs.get_attr_table(attr);
855  if (container) {
856  add_attributes(ncid, varid, *container, var_name, global_attr_name, is_nc_enhanced);
857  }
858  break;
859  }
860 
861  case Attr_byte: {
862  // unsigned char
863  vector<unsigned char> vals;
864  vals.resize(num_vals);
865  for (attri = 0; attri < num_vals; attri++) {
866  string val = attrs.get_attr(attr, attri);
867  istringstream is(val);
868  unsigned int uival = 0;
869  is >> uival;
870  vals[attri] = (unsigned char) uival;
871  }
872  stax = nc_put_att_uchar(ncid, varid, var_attr_name.c_str(), NC_UBYTE,
873  num_vals, &vals[0]);
874 #if !NDEBUG
875  if (stax != NC_NOERR) {
876  string err = (string) "File out netcdf, "
877  + "failed to write byte attribute " + var_attr_name;
878  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
879  }
880 #endif
881  break;
882  }
883 
884  case Attr_int16: {
885  // short
886  vector<short> vals;
887  vals.resize(num_vals);
888  for (attri = 0; attri < num_vals; attri++) {
889  string val = attrs.get_attr(attr, attri);
890  istringstream is(val);
891  short sval = 0;
892  is >> sval;
893  vals[attri] = sval;
894  }
895  stax = nc_put_att_short(ncid, varid, var_attr_name.c_str(), NC_SHORT, num_vals, &vals[0]);
896 #if !NDEBUG
897  if (stax != NC_NOERR) {
898  string err = (string) "File out netcdf, "
899  + "failed to write short attribute " + var_attr_name;
900  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
901  }
902 #endif
903 
904  break;
905  }
906 
907  case Attr_uint16: {
908  // unsigned short
909  // (needs to be big enough to store an unsigned short
910  //unsigned short vals[num_vals];
911  vector<unsigned short> vals;
912  vals.resize(num_vals);
913  for (attri = 0; attri < num_vals; attri++) {
914  string val = attrs.get_attr(attr, attri);
915  istringstream is(val);
916  unsigned short ival = 0;
917  is >> ival;
918  vals[attri] = ival;
919  }
920  stax = nc_put_att_ushort(ncid, varid, var_attr_name.c_str(), NC_USHORT, num_vals,
921  &vals[0]);
922 #if !NDEBUG
923  if (stax != NC_NOERR) {
924  string err = (string) "File out netcdf, "
925  + "failed to write unsinged short attribute " + var_attr_name;
926  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
927  }
928 #endif
929 
930  break;
931  }
932 
933  case Attr_int32: {
934  // int
935  //int vals[num_vals];
936  vector<int> vals;
937  vals.resize(num_vals);
938  for (attri = 0; attri < num_vals; attri++) {
939  string val = attrs.get_attr(attr, attri);
940  istringstream is(val);
941  int ival = 0;
942  is >> ival;
943  vals[attri] = ival;
944  }
945  stax = nc_put_att_int(ncid, varid, var_attr_name.c_str(), NC_INT, num_vals, &vals[0]);
946 
947 #if !NDEBUG
948  if (stax != NC_NOERR) {
949  string err = (string) "File out netcdf, "
950  + "failed to write int attribute " + var_attr_name;
951  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
952  }
953 #endif
954 
955  break;
956  }
957 
958  case Attr_uint32: {
959  // uint
960  //unsigned int vals[num_vals];
961  vector<unsigned int> vals;
962  vals.resize(num_vals);
963  for (attri = 0; attri < num_vals; attri++) {
964  string val = attrs.get_attr(attr, attri);
965  istringstream is(val);
966  unsigned int lval = 0;
967  is >> lval;
968  vals[attri] = lval;
969  }
970  stax = nc_put_att_uint(ncid, varid, var_attr_name.c_str(), NC_UINT, num_vals,
971  &vals[0]);
972 #if !NDEBUG
973  if (stax != NC_NOERR) {
974  string err = (string) "File out netcdf, "
975  + "failed to write byte attribute " + var_attr_name;
976  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
977  }
978 #endif
979 
980  break;
981  }
982 
983  case Attr_float32: {
984  // float
985  //float vals[num_vals];
986  vector<float> vals;
987  vals.resize(num_vals);
988  for (attri = 0; attri < num_vals; attri++) {
989  string val = attrs.get_attr(attr, attri);
990  const char *cval = val.c_str();
991  //istringstream is(val);
992  float fval = 0;
993  fval = strtod(cval,NULL);
994  //is >> fval;
995  vals[attri] = fval;
996  }
997  stax = nc_put_att_float(ncid, varid, var_attr_name.c_str(), NC_FLOAT, num_vals, &vals[0]);
998 
999 #if !NDEBUG
1000  if (stax != NC_NOERR) {
1001  string err = (string) "File out netcdf, "
1002  + "failed to write float attribute " + var_attr_name;
1003  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1004  }
1005 #endif
1006 
1007  break;
1008  }
1009 
1010  case Attr_float64: {
1011  // double
1012  //double vals[num_vals];
1013  vector<double> vals;
1014  vals.resize(num_vals);
1015  for (attri = 0; attri < num_vals; attri++) {
1016  string val = attrs.get_attr(attr, attri);
1017  const char *cval = val.c_str();
1018  //istringstream is(val);
1019  double dval = 0;
1020  dval = strtod(cval,NULL);
1021  //is >> dval;
1022  vals[attri] = dval;
1023  }
1024  stax = nc_put_att_double(ncid, varid, var_attr_name.c_str(), NC_DOUBLE, num_vals, &vals[0]);
1025 
1026 #if !NDEBUG
1027  if (stax != NC_NOERR) {
1028  string err = (string) "File out netcdf, "
1029  + "failed to write double attribute " + var_attr_name;
1030  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1031  }
1032 #endif
1033 
1034  break;
1035  }
1036 
1037  case Attr_string:
1038  case Attr_url:
1039  case Attr_other_xml: { // Added. jhrg 12.27.2011
1040  // string
1041  string val = attrs.get_attr(attr, 0);
1042  for (attri = 1; attri < num_vals; attri++) {
1043  val += "\n" + attrs.get_attr(attr, attri);
1044  }
1045  string attr_name = attrs.get_name(attr);
1046  if (attr_name != _FillValue) {
1047  stax = nc_put_att_text(ncid, varid, var_attr_name.c_str(), val.length(), val.c_str());
1048  }
1049  else {
1050  BESDEBUG("fonc",
1051  "FONcAttributes::add_attributes_worker - Original attribute value is first character: "
1052  << val.c_str()[0] << endl);
1053  stax = nc_put_att_text(ncid, varid, var_attr_name.c_str(), 1, val.c_str());
1054  if (stax == NC_NOERR) {
1055  // New name for attribute _FillValue with original value
1056  string var_attr_name_fillvalue = "Orig_FillValue";
1057  BESDEBUG("fonc",
1058  "FONcAttributes::add_attributes_worker - New attribute value is original value: "
1059  << val.c_str() << endl);
1060  // This line causes the segmentation fault since attrs is changed and the original iterator of attrs doesn't exist anymore.
1061  // So it causes the segmentation fault when next attribute is fetched in the for loop of the add_attributes(). KY 2019-12-13
1062  // Note: Leave the following #if 0 #endif for the time being.
1063 #if 0
1064  attrs.append_attr(var_attr_name_fillvalue,"String", val);
1065 #endif
1066  stax = nc_put_att_text(ncid, varid, var_attr_name_fillvalue.c_str(), val.length(), val.c_str());
1067  }
1068  }
1069 
1070 #if !NDEBUG
1071  if (stax != NC_NOERR) {
1072  string err = (string) "File out netcdf, "
1073  + "failed to write string attribute " + var_attr_name;
1074  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1075  }
1076 #endif
1077 
1078  break;
1079  }
1080 
1081 
1082  case Attr_unknown:
1083  default: {
1084  string err = (string) "File out netcdf, failed to write unknown type of attribute " + var_attr_name;
1085  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1086  break; // Not actually needed since FONcUtils::handle_error throws
1087  }
1088  }
1089 
1090  if (stax != NC_NOERR) {
1091  string err = (string) "File out netcdf, failed to write " + attr_type + " attribute " + var_attr_name;
1092  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1093  }
1094 }
1095 
1108 void
1110  int varid,
1111  const string &var_name,
1112  const string &global_attr_name,
1113  const string &var_attr_name,
1114  D4Attribute* attr,
1115  bool is_nc_enhanced) {
1116 
1117  D4AttributeType d4_attr_type = attr->type();
1118  int stax = NC_NOERR;
1119  unsigned int attri = 0;
1120  unsigned int num_vals = attr->num_values();
1121  switch (d4_attr_type) {
1122  case attr_container_c: {
1123  // flatten
1124  BESDEBUG("fonc", "This is an attribute container. attr_name: \"" << global_attr_name << "\"" << endl);
1125  D4Attributes *c_attributes = attr->attributes();
1126  if (c_attributes) {
1127  add_dap4_attributes(ncid, varid, c_attributes, var_name, global_attr_name, is_nc_enhanced);
1128  }
1129  }
1130  break;
1131  case attr_byte_c:
1132  case attr_uint8_c:{
1133  // unsigned char
1134  vector<unsigned char> vals;
1135  vals.resize(num_vals);
1136  attri = 0;
1137  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1138  string val = *vi;
1139  istringstream is(val);
1140  unsigned int uival = 0;
1141  is >> uival;
1142  vals[attri] = (unsigned char) uival;
1143  ++attri;
1144  }
1145  stax = nc_put_att_uchar(ncid, varid, var_attr_name.c_str(), NC_UBYTE,
1146  num_vals, &vals[0]);
1147  if (stax != NC_NOERR) {
1148  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1149  + "failed to write byte attribute " + var_attr_name;
1150  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1151  }
1152  }
1153  break;
1154  case attr_int8_c:{
1155  // 8-bit integer
1156  vector<int8_t> vals;
1157  vals.resize(num_vals);
1158  attri = 0;
1159  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1160  string val = *vi;
1161  istringstream is(val);
1162  int uival = 0;
1163  is >> uival;
1164  vals[attri] = (int8_t) uival;
1165  ++attri;
1166  }
1167  stax = nc_put_att_schar(ncid, varid, var_attr_name.c_str(), NC_BYTE,
1168  num_vals, &vals[0]);
1169  if (stax != NC_NOERR) {
1170  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1171  + "failed to write signed 8-bit integer attribute " + var_attr_name;
1172  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1173  }
1174  }
1175  break;
1176  case attr_int16_c: {
1177  // short
1178  vector<short> vals;
1179  vals.resize(num_vals);
1180  attri = 0;
1181  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1182  string val = *vi;
1183  istringstream is(val);
1184  short sval = 0;
1185  is >> sval;
1186  vals[attri] = sval;
1187  ++attri;
1188  }
1189 
1190  stax = nc_put_att_short(ncid, varid, var_attr_name.c_str(), NC_SHORT,
1191  num_vals, &vals[0]);
1192  if (stax != NC_NOERR) {
1193  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1194  + "failed to write short attribute " + var_attr_name;
1195  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1196  }
1197  }
1198  break;
1199  case attr_uint16_c: {
1200  // unsigned short
1201  attri = 0;
1202  vector<unsigned short>vals;
1203  vals.resize(num_vals);
1204  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1205  string val = *vi;
1206  istringstream is(val);
1207  unsigned short ival = 0;
1208  is >> ival;
1209  vals[attri] = ival;
1210  ++attri;
1211  }
1212 
1213  stax = nc_put_att_ushort(ncid, varid, var_attr_name.c_str(), NC_USHORT, num_vals,
1214  &vals[0]);
1215  if (stax != NC_NOERR) {
1216  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1217  + "failed to write unsigned short attribute " + var_attr_name;
1218  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1219  }
1220  }
1221  break;
1222  case attr_int32_c: {
1223  vector<int> vals;
1224  vals.resize(num_vals);
1225  attri = 0;
1226  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1227  string val = *vi;
1228  istringstream is(val);
1229  int sval = 0;
1230  is >> sval;
1231  vals[attri] = sval;
1232  ++attri;
1233  }
1234 
1235  stax = nc_put_att_int(ncid, varid, var_attr_name.c_str(), NC_INT, num_vals,
1236  &vals[0]);
1237  if (stax != NC_NOERR) {
1238  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1239  + "failed to write int attribute " + var_attr_name;
1240  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1241  }
1242  }
1243  break;
1244  case attr_uint32_c: {
1245  // uint
1246  vector<unsigned int> vals;
1247  vals.resize(num_vals);
1248  attri = 0;
1249  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1250  string val = *vi;
1251  istringstream is(val);
1252  unsigned int sval = 0;
1253  is >> sval;
1254  vals[attri] = sval;
1255  ++attri;
1256  }
1257 
1258  stax = nc_put_att_uint(ncid, varid, var_attr_name.c_str(), NC_UINT, num_vals,
1259  &vals[0]);
1260  if (stax != NC_NOERR) {
1261  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1262  + "failed to write unsigned int attribute " + var_attr_name;
1263  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1264  }
1265  }
1266  break;
1267  case attr_int64_c: {
1268  vector<long long> vals;
1269  vals.resize(num_vals);
1270  attri = 0;
1271  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1272  string val = *vi;
1273  istringstream is(val);
1274  long long sval = 0;
1275  is >> sval;
1276  vals[attri] = sval;
1277  ++attri;
1278  }
1279 
1280  stax = nc_put_att_longlong(ncid, varid, var_attr_name.c_str(), NC_INT64, num_vals,
1281  &vals[0]);
1282  if (stax != NC_NOERR) {
1283  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1284  + "failed to write 64-bit int attribute " + var_attr_name;
1285  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1286  }
1287  }
1288  break;
1289  case attr_uint64_c: {
1290  vector<unsigned long long> vals;
1291  vals.resize(num_vals);
1292  attri = 0;
1293  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1294  string val = *vi;
1295  istringstream is(val);
1296  unsigned long long sval = 0;
1297  is >> sval;
1298  vals[attri] = sval;
1299  ++attri;
1300  }
1301 
1302  stax = nc_put_att_ulonglong(ncid, varid, var_attr_name.c_str(), NC_UINT64, num_vals,
1303  &vals[0]);
1304  if (stax != NC_NOERR) {
1305  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1306  + "failed to write unsigned 64-bit int attribute " + var_attr_name;
1307  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1308  }
1309  }
1310  break;
1311 
1312  case attr_float32_c: {
1313  vector<float>vals;
1314  vals.resize(num_vals);
1315  attri = 0;
1316  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1317  string val = *vi;
1318  const char *cval = val.c_str();
1319  //istringstream is(val);
1320  float sval = 0;
1321  sval = strtod(cval,NULL);
1322  //is >> sval;
1323  vals[attri] = sval;
1324  ++attri;
1325  }
1326 
1327  stax = nc_put_att_float(ncid, varid, var_attr_name.c_str(), NC_FLOAT,
1328  num_vals, &vals[0]);
1329  if (stax != NC_NOERR) {
1330  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1331  + "failed to write float attribute " + var_attr_name;
1332  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1333  }
1334  }
1335  break;
1336  case attr_float64_c: {
1337  vector<double> vals;
1338  vals.resize(num_vals);
1339  attri = 0;
1340  for (D4Attribute::D4AttributeIter vi = attr->value_begin(), ve = attr->value_end(); vi != ve; vi++) {
1341  string val = *vi;
1342  const char *cval = val.c_str();
1343  //istringstream is(val);
1344  double sval = 0;
1345  sval = strtod(cval,NULL);
1346  //is >> sval;
1347  vals[attri] = sval;
1348  ++attri;
1349  }
1350  stax = nc_put_att_double(ncid, varid, var_attr_name.c_str(), NC_DOUBLE,
1351  num_vals, &vals[0]);
1352  if (stax != NC_NOERR) {
1353  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1354  + "failed to write double attribute " + var_attr_name;
1355  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1356  }
1357  }
1358  break;
1359  case attr_str_c:
1360  case attr_url_c:
1361  case attr_otherxml_c: // Added. jhrg 12.27.2011
1362  {
1363 
1364  if(attr->num_values()==0)
1365  stax = nc_put_att_text(ncid, varid, var_attr_name.c_str(), 0, "");
1366  else {
1367 
1368  D4Attribute::D4AttributeIter vi,ve;
1369  vi = attr->value_begin();
1370  ve = attr->value_end();
1371 
1372 
1373  string val = (*vi);
1374 
1375  vi++;
1376  for (; vi != ve; vi++) {
1377  val += "\n" + *vi;
1378  }
1379 
1380  if (var_attr_name != _FillValue) {
1381  stax = nc_put_att_text(ncid, varid, var_attr_name.c_str(), val.length(), val.c_str());
1382  } else {
1383  BESDEBUG("fonc",
1384  "FONcAttributes::add_attributes_worker - Original attribute value is first character: "
1385  << val.c_str()[0] << endl);
1386  stax = nc_put_att_text(ncid, varid, var_attr_name.c_str(), 1, val.c_str());
1387  if (stax == NC_NOERR) {
1388  // New name for attribute _FillValue with original value
1389  string var_attr_name_fillvalue = "Orig_FillValue";
1390  BESDEBUG("fonc",
1391  "FONcAttributes::add_attributes_worker - New attribute value is original value: "
1392  << val.c_str() << endl);
1393  // This line causes the segmentation fault since attrs is changed and the original iterator of attrs doesn't exist anymore.
1394  // So it causes the segmentation fault when next attribute is fetched in the for loop of the add_attributes(). KY 2019-12-13
1395  #if 0
1396  attrs.append_attr(var_attr_name_fillvalue,"String", val);
1397  #endif
1398  stax = nc_put_att_text(ncid, varid, var_attr_name_fillvalue.c_str(), val.length(), val.c_str());
1399  }
1400  }
1401  }
1402 
1403  if (stax != NC_NOERR) {
1404  string err = (string) "File out netcdf-4 enhanced for DAP4, "
1405  + "failed to write string attribute " + var_attr_name;
1406  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1407  }
1408  }
1409  break;
1410 
1411  case attr_null_c:
1412  case attr_enum_c:
1413  case attr_opaque_c:
1414  {
1415  string err = (string) "File out netcdf, "
1416  + "failed to write unknown type of attribute " + var_attr_name;
1417  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1418  }
1419  break;
1420  }
1421 }
1422 
1423 // Note: Leave the following #if 0 #endif block for the time being. They can be removed in the future
1424 // release. KY 2021-06-15
1425 #if 0
1426  int stax = NC_NOERR;
1427  AttrType attrType = attrs.get_attr_type(attr);
1428  unsigned int attri = 0;
1429  unsigned int num_vals = attrs.get_attr_num(attr);
1430  switch (attrType) {
1431  case Attr_container: {
1432  // flatten
1433  BESDEBUG("fonc", "This is an attribute container. attr_name: \"" << global_attr_name << "\"" << endl);
1434  AttrTable *container = attrs.get_attr_table(attr);
1435  if (container) {
1436  add_attributes(ncid, varid, *container, var_name, global_attr_name, is_nc_enhanced);
1437  }
1438  }
1439  break;
1440  case Attr_byte: {
1441  // unsigned char
1442  //unsigned char vals[num_vals];
1443  vector<unsigned char> vals;
1444  vals.resize(num_vals);
1445  for (attri = 0; attri < num_vals; attri++) {
1446  string val = attrs.get_attr(attr, attri);
1447  istringstream is(val);
1448  unsigned int uival = 0;
1449  is >> uival;
1450  vals[attri] = (unsigned char) uival;
1451  }
1452  stax = nc_put_att_uchar(ncid, varid, var_attr_name.c_str(), NC_UBYTE,
1453  num_vals, &vals[0]);
1454  if (stax != NC_NOERR) {
1455  string err = (string) "File out netcdf, "
1456  + "failed to write byte attribute " + var_attr_name;
1457  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1458  }
1459  }
1460  break;
1461  case Attr_int16: {
1462  // short
1463  //short vals[num_vals];
1464  vector<short> vals;
1465  vals.resize(num_vals);
1466  for (attri = 0; attri < num_vals; attri++) {
1467  string val = attrs.get_attr(attr, attri);
1468  istringstream is(val);
1469  short sval = 0;
1470  is >> sval;
1471  vals[attri] = sval;
1472  }
1473  stax = nc_put_att_short(ncid, varid, var_attr_name.c_str(), NC_SHORT,
1474  num_vals, &vals[0]);
1475  if (stax != NC_NOERR) {
1476  string err = (string) "File out netcdf, "
1477  + "failed to write short attribute " + var_attr_name;
1478  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1479  }
1480  }
1481  break;
1482  case Attr_uint16: {
1483  // unsigned short
1484  // (needs to be big enough to store an unsigned short
1485  //unsigned short vals[num_vals];
1486  vector<unsigned short> vals;
1487  vals.resize(num_vals);
1488  for (attri = 0; attri < num_vals; attri++) {
1489  string val = attrs.get_attr(attr, attri);
1490  istringstream is(val);
1491  unsigned short ival = 0;
1492  is >> ival;
1493  vals[attri] = ival;
1494  }
1495  stax = nc_put_att_ushort(ncid, varid, var_attr_name.c_str(), NC_USHORT, num_vals,
1496  &vals[0]);
1497  if (stax != NC_NOERR) {
1498  string err = (string) "File out netcdf, "
1499  + "failed to write unsinged short attribute " + var_attr_name;
1500  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1501  }
1502  }
1503  break;
1504  case Attr_int32: {
1505  // int
1506  //int vals[num_vals];
1507  vector<int> vals;
1508  vals.resize(num_vals);
1509  for (attri = 0; attri < num_vals; attri++) {
1510  string val = attrs.get_attr(attr, attri);
1511  istringstream is(val);
1512  int ival = 0;
1513  is >> ival;
1514  vals[attri] = ival;
1515  }
1516  stax = nc_put_att_int(ncid, varid, var_attr_name.c_str(), NC_INT, num_vals,
1517  &vals[0]);
1518  if (stax != NC_NOERR) {
1519  string err = (string) "File out netcdf, "
1520  + "failed to write int attribute " + var_attr_name;
1521  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1522  }
1523  }
1524  break;
1525  case Attr_uint32: {
1526  // uint
1527  //unsigned int vals[num_vals];
1528  vector<unsigned int> vals;
1529  vals.resize(num_vals);
1530  for (attri = 0; attri < num_vals; attri++) {
1531  string val = attrs.get_attr(attr, attri);
1532  istringstream is(val);
1533  unsigned int lval = 0;
1534  is >> lval;
1535  vals[attri] = lval;
1536  }
1537  stax = nc_put_att_uint(ncid, varid, var_attr_name.c_str(), NC_UINT, num_vals,
1538  &vals[0]);
1539  if (stax != NC_NOERR) {
1540  string err = (string) "File out netcdf, "
1541  + "failed to write byte attribute " + var_attr_name;
1542  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1543  }
1544  }
1545  break;
1546  case Attr_float32: {
1547  // float
1548  //float vals[num_vals];
1549  vector<float> vals;
1550  vals.resize(num_vals);
1551  for (attri = 0; attri < num_vals; attri++) {
1552  string val = attrs.get_attr(attr, attri);
1553  const char *cval = val.c_str();
1554  //istringstream is(val);
1555  float fval = 0;
1556  fval = strtod(cval,NULL);
1557  //is >> fval;
1558  vals[attri] = fval;
1559  }
1560  stax = nc_put_att_float(ncid, varid, var_attr_name.c_str(), NC_FLOAT,
1561  num_vals, &vals[0]);
1562  if (stax != NC_NOERR) {
1563  string err = (string) "File out netcdf, "
1564  + "failed to write float attribute " + var_attr_name;
1565  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1566  }
1567  }
1568  break;
1569  case Attr_float64: {
1570  // double
1571  //double vals[num_vals];
1572  vector<double> vals;
1573  vals.resize(num_vals);
1574  for (attri = 0; attri < num_vals; attri++) {
1575  string val = attrs.get_attr(attr, attri);
1576  const char *cval = val.c_str();
1577  //istringstream is(val);
1578  double dval = 0;
1579  dval = strtod(cval,NULL);
1580  //is >> dval;
1581  vals[attri] = dval;
1582  }
1583  stax = nc_put_att_double(ncid, varid, var_attr_name.c_str(), NC_DOUBLE,
1584  num_vals, &vals[0]);
1585  if (stax != NC_NOERR) {
1586  string err = (string) "File out netcdf, "
1587  + "failed to write double attribute " + var_attr_name;
1588  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1589  }
1590  }
1591  break;
1592  case Attr_string:
1593  case Attr_url:
1594  case Attr_other_xml: // Added. jhrg 12.27.2011
1595  {
1596  // string
1597  string val = attrs.get_attr(attr, 0);
1598  for (attri = 1; attri < num_vals; attri++) {
1599  val += "\n" + attrs.get_attr(attr, attri);
1600  }
1601  string attr_name = attrs.get_name(attr);
1602  if (attr_name != _FillValue) {
1603  stax = nc_put_att_text(ncid, varid, var_attr_name.c_str(), val.length(), val.c_str());
1604  } else {
1605  BESDEBUG("fonc",
1606  "FONcAttributes::add_attributes_worker - Original attribute value is first character: "
1607  << val.c_str()[0] << endl);
1608  stax = nc_put_att_text(ncid, varid, var_attr_name.c_str(), 1, val.c_str());
1609  if (stax == NC_NOERR) {
1610  // New name for attribute _FillValue with original value
1611  string var_attr_name_fillvalue = "Orig_FillValue";
1612  BESDEBUG("fonc",
1613  "FONcAttributes::add_attributes_worker - New attribute value is original value: "
1614  << val.c_str() << endl);
1615  // This line causes the segmentation fault since attrs is changed and the original iterator of attrs doesn't exist anymore.
1616  // So it causes the segmentation fault when next attribute is fetched in the for loop of the add_attributes(). KY 2019-12-13
1617 #if 0
1618  attrs.append_attr(var_attr_name_fillvalue,"String", val);
1619 #endif
1620  stax = nc_put_att_text(ncid, varid, var_attr_name_fillvalue.c_str(), val.length(), val.c_str());
1621  }
1622  }
1623 
1624  if (stax != NC_NOERR) {
1625  string err = (string) "File out netcdf, "
1626  + "failed to write string attribute " + var_attr_name;
1627  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1628  }
1629  }
1630  break;
1631 
1632  case Attr_unknown: {
1633  string err = (string) "File out netcdf, "
1634  + "failed to write unknown type of attribute " + var_attr_name;
1635  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
1636  }
1637  break;
1638  }
1639 
1640 #endif
1641 
static bool endsWith(std::string const &fullString, std::string const &ending)
Definition: BESUtil.cc:961
static void add_dap4_attributes(int ncid, int varid, D4Attributes *d4_attrs, const string &var_name, const string &prepend_attr, bool is_netCDF_enhanced)
add_dap4_attributes
static void write_dap4_attrs_for_nc4_types(int ncid, int varid, const string &var_name, const string &global_attr_name, const string &var_attr_name, D4Attribute *attr, bool is_nc_enhanced)
writes out a single attribute that maps the dap4 datatype to netCDF-4
static void add_original_name(int ncid, int varid, const string &var_name, const string &orig)
Adds an attribute for the variable if the variable name had to be modified in any way.
static void add_attributes(int ncid, int varid, AttrTable &attrs, const string &var_name, const string &prepend_attr, bool is_netCDF_enhanced)
helper function for add_attributes
static void write_attrs_for_nc4_types(int ncid, int varid, const string &var_name, const string &global_attr_name, const string &var_attr_name, AttrTable attrs, AttrTable::Attr_iter &attr, bool is_nc_enhanced)
writes out a single attribute that maps the datatype to netCDF-4
static void add_variable_attributes(int ncid, int varid, BaseType *b, bool is_netCDF_enhanced, bool is_dap4)
Add the attributes for an OPeNDAP variable to the netcdf file.
static void handle_error(int stax, const string &err, const string &file, int line)
handle any netcdf errors
Definition: FONcUtils.cc:424
static string id2netcdf(string in)
convert the provided string to a netcdf allowed identifier.
Definition: FONcUtils.cc:84