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